diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..c53888a24 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,8 @@ +### Description of the feature or fix + +A clear and concise description of what the bug or new feature is. + +### Checkpoints +- [ ] Follow the [styling guide](https://github.com/lvgl/lvgl/blob/master/docs/CODING_STYLE.md) +- [ ] Update CHANGELOG.md +- [ ] Update the documentation diff --git a/CHANGELOG.md b/CHANGELOG.md index 6294f639a..60de130b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,27 @@ # Changelog -## v7.8.0 (Planned to 01.12.2020) +## v7.9.0 + +### New features +- feat(chart) add lv_chart_remove_series and lv_chart_hide_series +- feat(img_cahce) allow disabling image cacheing +- calendar: make get_day_of_week() public + +### Bugfixes +- fix(draw_rect) free buffer used for arabic processing +- fix(win) arabic process the title of the window +- fix(dropdown) arabic process the option in lv_dropdown_add_option +- fix(textarea) buffer overflow in password mode with UTF-8 characters +- fix(textarea) cursor position after hiding character in password mode +- fix(linemeter) draw critical lines with correct color + +## v7.8.1 (Plannad at 15.12.2020) + +### Bugfixes +- fix(lv_scr_load_anim) fix when multiple screen are loaded at tsame time with delay +- fix(page) fix LV_SCOLLBAR_MODE_DRAG + +## v7.8.0 (01.12.2020) ### New features - make DMA2D non blocking diff --git a/CMakeLists.txt b/CMakeLists.txt index 114db196b..7f9caf709 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,30 @@ if(ESP_PLATFORM) file(GLOB_RECURSE SOURCES src/*.c) idf_component_register(SRCS ${SOURCES} - INCLUDE_DIRS . src) + INCLUDE_DIRS . src + REQUIRES main) target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE") -target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_SKIP") + +if (CONFIG_LV_MEM_CUSTOM) + if (CONFIG_LV_MEM_CUSTOM_ALLOC) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_MEM_CUSTOM_ALLOC=${CONFIG_LV_MEM_CUSTOM_ALLOC}") + endif() + + if (CONFIG_LV_MEM_CUSTOM_FREE) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_MEM_CUSTOM_FREE=${CONFIG_LV_MEM_CUSTOM_FREE}") + endif() +endif() + +if (CONFIG_LV_TICK_CUSTOM) + if (CONFIG_LV_TICK_CUSTOM_SYS_TIME_EXPR) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_TICK_CUSTOM_SYS_TIME_EXPR=${CONFIG_LV_TICK_CUSTOM_SYS_TIME_EXPR}") + endif() +endif() + +if (CONFIG_LV_USER_DATA_FREE) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_USER_DATA_FREE=${CONFIG_LV_USER_DATA_FREE}") +endif() if (CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM) target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR") diff --git a/Kconfig b/Kconfig index 9eaf97a4a..adddb034e 100644 --- a/Kconfig +++ b/Kconfig @@ -1,4 +1,4 @@ -# Kconfig file for LVGL v7.7.1 +# Kconfig file for LVGL v7.8.1 menu "LVGL configuration" @@ -105,11 +105,38 @@ menu "LVGL configuration" displays. menu "Memory manager settings" + config LV_MEM_CUSTOM + bool + prompt "If true use custom malloc/free, otherwise use the built-in `lv_mem_alloc` and `lv_mem_free`" + + config LV_MEM_CUSTOM_INCLUDE + string + prompt "Header to include for the custom memory function" + default stdlib.h + depends on LV_MEM_CUSTOM + + config LV_MEM_CUSTOM_ALLOC + string + prompt "Wrapper to malloc" + default malloc + depends on LV_MEM_CUSTOM + + config LV_MEM_CUSTOM_FREE + string + prompt "Wrapper to free" + default free + depends on LV_MEM_CUSTOM + config LV_MEM_SIZE_BYTES int prompt "Size of the memory used by `lv_mem_alloc` in kilobytes (>= 2kB)" range 2 128 - default 32 + default 32 + depends on !LV_MEM_CUSTOM + + config LV_MEMCPY_MEMSET_STD + bool + prompt "Use the standard memcpy and memset instead of LVGL's own functions" endmenu menu "Indev device settings" @@ -204,6 +231,17 @@ menu "LVGL configuration" default y if !LV_CONF_MINIMAL config LV_USE_USER_DATA bool "Add a 'user_data' to drivers and objects." + config LV_USE_USER_DATA_FREE + bool "Free the user data field upon object deletion" + depends on LV_USE_USER_DATA + config LV_USER_DATA_FREE_INCLUDE + string "Header for user data free function" + default "something.h" + depends on LV_USE_USER_DATA_FREE + config LV_USER_DATA_FREE + string "Invoking for user data free function. It has the lv_obj_t pointer as single parameter." + default "(user_data_free)" + depends on LV_USE_USER_DATA_FREE config LV_USE_PERF_MONITOR bool "Show CPU usage and FPS count in the right bottom corner." config LV_USE_API_EXTENSION_V6 @@ -235,11 +273,29 @@ menu "LVGL configuration" LV_IMG_CACHE_DEF_SIZE must be >= 1 endmenu - menu "Compiler settings" + menu "Compiler Settings" config LV_BIG_ENDIAN_SYSTEM bool "For big endian systems set to 1" endmenu + menu "HAL Settings" + config LV_TICK_CUSTOM + bool + prompt "Use a custom tick source" + + config LV_TICK_CUSTOM_INCLUDE + string + prompt "Header for the system time function" + default Arduino.h + depends on LV_TICK_CUSTOM + + config LV_TICK_CUSTOM_SYS_TIME_EXPR + string + prompt "Expression evaluating to current system time in ms" + default "(millis())" + depends on LV_TICK_CUSTOM + endmenu + menu "Log Settings" config LV_USE_LOG bool "Enable the log module" diff --git a/lv_conf_template.h b/lv_conf_template.h index 0c65b9216..f8815472f 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -244,7 +244,7 @@ typedef void * lv_fs_drv_user_data_t; * (I.e. no new image decoder is added) * With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. * However the opened images might consume additional RAM. - * LV_IMG_CACHE_DEF_SIZE must be >= 1 */ + * Set it to 0 to disable caching */ #define LV_IMG_CACHE_DEF_SIZE 1 /*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/ diff --git a/scripts/release/com.py b/scripts/release/com.py index 2bd77edd1..bb3fd7ddd 100755 --- a/scripts/release/com.py +++ b/scripts/release/com.py @@ -85,10 +85,10 @@ def update_version(ver): templ = fnmatch.filter(os.listdir('.'), '*_templ*.h') - if len(templ) > 0 and templ[0]: + if len(templ) > 0 and templ[0]: print("Updating version in " + templ[0]) - cmd("sed -i -r 's/v[0-9]+\.[0-9]+\.[0-9]+/"+ "v" + ver_num + "/' " + templ[0]) - + cmd("sed -i -r 's/v[0-9]+\.[0-9]+\.[0-9]+.*/"+ "v" + ver_num + "/' " + templ[0]) + if os.path.exists("library.json"): print("Updating version in library.json") cmd("sed -i -r 's/[0-9]+\.[0-9]+\.[0-9]+/"+ ver_num +"/' library.json") @@ -100,6 +100,9 @@ def update_version(ver): if path.exists("conf.py"): cmd("sed -i -r \"s/'v[0-9]+\.[0-9]+\.[0-9]+.*'/\'" + ver_str + "'/\" conf.py") + if path.exists("Kconfig"): + cmd("sed -i -r \"s/'v[0-9]+\.[0-9]+\.[0-9]+.*'/\'" + ver_str + "'/\" Kconfig") + if path.exists("lvgl.h"): define_set("./lvgl.h", "LVGL_VERSION_MAJOR", str(ver[0])) define_set("./lvgl.h", "LVGL_VERSION_MINOR", str(ver[1])) diff --git a/scripts/release/main.py b/scripts/release/main.py index 4dd2e1fac..a96d11fc3 100755 --- a/scripts/release/main.py +++ b/scripts/release/main.py @@ -55,7 +55,7 @@ if __name__ == '__main__': print("Invalid argument. Usage ./release.py bugfix | minor | major") exit(1) - os.chdir(workdir) + #os.chdir(workdir) clone_repos() release.make() for p in proj_list: diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 7b8721754..592d54d3b 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -201,7 +201,7 @@ # endif #endif -/* Complier prefix for a big array declaration */ +/* Compiler prefix for a big array declaration */ #ifndef LV_MEM_ATTR # ifdef CONFIG_LV_MEM_ATTR # define LV_MEM_ATTR CONFIG_LV_MEM_ATTR @@ -330,7 +330,7 @@ #endif /* Long press time in milliseconds. - * Time to send `LV_EVENT_LONG_PRESSSED`) */ + * Time to send `LV_EVENT_LONG_PRESSED`) */ #ifndef LV_INDEV_DEF_LONG_PRESS_TIME # ifdef CONFIG_LV_INDEV_DEF_LONG_PRESS_TIME # define LV_INDEV_DEF_LONG_PRESS_TIME CONFIG_LV_INDEV_DEF_LONG_PRESS_TIME @@ -1312,7 +1312,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ /* Support bidirectional texts. * Allows mixing Left-to-Right and Right-to-Left texts. - * The direction will be processed according to the Unicode Bidirectioanl Algorithm: + * The direction will be processed according to the Unicode Bidirectional Algorithm: * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ #ifndef LV_USE_BIDI # ifdef CONFIG_LV_USE_BIDI diff --git a/src/lv_core/lv_disp.c b/src/lv_core/lv_disp.c index df6925b02..b02cdd3b1 100644 --- a/src/lv_core/lv_disp.c +++ b/src/lv_core/lv_disp.c @@ -195,6 +195,20 @@ void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa) void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del) { lv_disp_t * d = lv_obj_get_disp(new_scr); + lv_obj_t * act_scr = lv_scr_act(); + + + if(d->del_prev && act_scr != d->scr_to_load) { + lv_obj_del(act_scr); + lv_disp_load_scr(d->scr_to_load); + lv_anim_del(d->scr_to_load, NULL); + lv_obj_set_pos(d->scr_to_load, 0, 0); + lv_style_remove_prop(lv_obj_get_local_style(d->scr_to_load, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); + + act_scr = d->scr_to_load; + } + + d->scr_to_load = new_scr; if(d->prev_scr && d->del_prev) { lv_obj_del(d->prev_scr); @@ -377,13 +391,13 @@ static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v) // lv_obj_set_style_bg_color(obj, LV_PART_MAIN, LV_STATE_DEFAULT, v); } - static void scr_anim_ready(lv_anim_t * a) { lv_disp_t * d = lv_obj_get_disp(a->var); if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr); d->prev_scr = NULL; + d->scr_to_load = NULL; lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_PART_MAIN, LV_STATE_DEFAULT), LV_STYLE_OPA); } #endif diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index bbf74ca99..c2049ade0 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -165,8 +165,9 @@ void lv_init(void) _lv_indev_init(); _lv_img_decoder_init(); +#if LV_IMG_CACHE_DEF_SIZE lv_img_cache_set_size(LV_IMG_CACHE_DEF_SIZE); - +#endif /*Test if the IDE has UTF-8 encoding*/ char * txt = "Á"; diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 1e6de095f..0ad15f0c6 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -40,6 +40,7 @@ LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const bool chroma_key, bool alpha_byte); static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg); +static void draw_cleanup(lv_img_cache_entry_t * cache); /********************** * STATIC VARIABLES @@ -267,9 +268,10 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_area_t mask_com; /*Common area of mask and coords*/ bool union_ok; union_ok = _lv_area_intersect(&mask_com, clip_area, &map_area_rot); + /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ if(union_ok == false) { - return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn - successfully.*/ + draw_cleanup(cdsc); + return LV_RES_OK; } lv_draw_map(coords, &mask_com, cdsc->dec_dsc.img_data, draw_dsc, chroma_keyed, alpha_byte); @@ -279,9 +281,10 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_area_t mask_com; /*Common area of mask and coords*/ bool union_ok; union_ok = _lv_area_intersect(&mask_com, clip_area, coords); + /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ if(union_ok == false) { - return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn - successfully.*/ + draw_cleanup(cdsc); + return LV_RES_OK; } int32_t width = lv_area_get_width(&mask_com); @@ -306,6 +309,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_img_decoder_close(&cdsc->dec_dsc); LV_LOG_WARN("Image draw can't read the line"); _lv_mem_buf_release(buf); + draw_cleanup(cdsc); return LV_RES_INV; } @@ -318,6 +322,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, _lv_mem_buf_release(buf); } + draw_cleanup(cdsc); return LV_RES_OK; } @@ -649,3 +654,13 @@ static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, co lv_draw_label(coords, clip_area, &label_dsc, msg, NULL); } +static void draw_cleanup(lv_img_cache_entry_t * cache) +{ +/*Automatically close images with no caching*/ +#if LV_IMG_CACHE_DEF_SIZE == 0 + lv_img_decoder_close(&cache->dec_dsc); +#else + LV_UNUSED(cache); +#endif +} + diff --git a/src/lv_draw/lv_draw_rect.c b/src/lv_draw/lv_draw_rect.c index 754df8b4c..5f9bfda08 100644 --- a/src/lv_draw/lv_draw_rect.c +++ b/src/lv_draw/lv_draw_rect.c @@ -1241,6 +1241,10 @@ static void draw_content(const lv_area_t * coords, const lv_area_t * clip, const if(src_type == LV_IMG_SRC_SYMBOL) lv_draw_label(&coords_tmp, clip, &label_dsc, dsc->content_src, NULL); else lv_draw_img(&coords_tmp, clip, dsc->content_src, &img_dsc); + +#if LV_USE_ARABIC_PERSIAN_CHARS + _lv_mem_buf_release(str); +#endif } #endif diff --git a/src/lv_draw/lv_img_cache.c b/src/lv_draw/lv_img_cache.c index cef32144f..2488865c3 100644 --- a/src/lv_draw/lv_img_cache.c +++ b/src/lv_draw/lv_img_cache.c @@ -19,7 +19,7 @@ /********************* * DEFINES *********************/ -/*Decrement life with this value in every open*/ +/*Decrement life with this value on every open*/ #define LV_IMG_CACHE_AGING 1 /*Boost life by this factor (multiply time_to_open with this value)*/ @@ -29,10 +29,6 @@ * "die" from very high values */ #define LV_IMG_CACHE_LIFE_LIMIT 1000 -#if LV_IMG_CACHE_DEF_SIZE < 1 - #error "LV_IMG_CACHE_DEF_SIZE must be >= 1. See lv_conf.h" -#endif - /********************** * TYPEDEFS **********************/ @@ -40,11 +36,16 @@ /********************** * STATIC PROTOTYPES **********************/ +#if LV_IMG_CACHE_DEF_SIZE == 0 +static lv_img_cache_entry_t cache_temp; +#endif /********************** * STATIC VARIABLES **********************/ +#if LV_IMG_CACHE_DEF_SIZE static uint16_t entry_cnt; +#endif /********************** * MACROS @@ -64,6 +65,10 @@ static uint16_t entry_cnt; */ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) { + /*Is the image cached?*/ + lv_img_cache_entry_t * cached_src = NULL; + +#if LV_IMG_CACHE_DEF_SIZE if(entry_cnt == 0) { LV_LOG_WARN("lv_img_cache_open: the cache size is 0"); return NULL; @@ -79,8 +84,6 @@ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) } } - /*Is the image cached?*/ - lv_img_cache_entry_t * cached_src = NULL; for(i = 0; i < entry_cnt; i++) { bool match = false; lv_img_src_t src_type = lv_img_src_get_type(cache[i].dec_dsc.src); @@ -104,48 +107,51 @@ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) } /*The image is not cached then cache it now*/ - if(cached_src == NULL) { - /*Find an entry to reuse. Select the entry with the least life*/ - cached_src = &cache[0]; - for(i = 1; i < entry_cnt; i++) { - if(cache[i].life < cached_src->life) { - cached_src = &cache[i]; - } - } + if(cached_src) return cached_src; - /*Close the decoder to reuse if it was opened (has a valid source)*/ - if(cached_src->dec_dsc.src) { - lv_img_decoder_close(&cached_src->dec_dsc); - LV_LOG_INFO("image draw: cache miss, close and reuse an entry"); + /*Find an entry to reuse. Select the entry with the least life*/ + cached_src = &cache[0]; + for(i = 1; i < entry_cnt; i++) { + if(cache[i].life < cached_src->life) { + cached_src = &cache[i]; } - else { - LV_LOG_INFO("image draw: cache miss, cached to an empty entry"); - } - - /*Open the image and measure the time to open*/ - uint32_t t_start; - t_start = lv_tick_get(); - cached_src->dec_dsc.time_to_open = 0; - lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color); - if(open_res == LV_RES_INV) { - LV_LOG_WARN("Image draw cannot open the image resource"); - lv_img_decoder_close(&cached_src->dec_dsc); - _lv_memset_00(&cached_src->dec_dsc, sizeof(lv_img_decoder_dsc_t)); - _lv_memset_00(cached_src, sizeof(lv_img_cache_entry_t)); - cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its use */ - return NULL; - } - - cached_src->life = 0; - - /*If `time_to_open` was not set in the open function set it here*/ - if(cached_src->dec_dsc.time_to_open == 0) { - cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start); - } - - if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1; } + /*Close the decoder to reuse if it was opened (has a valid source)*/ + if(cached_src->dec_dsc.src) { + lv_img_decoder_close(&cached_src->dec_dsc); + LV_LOG_INFO("image draw: cache miss, close and reuse an entry"); + } + else { + LV_LOG_INFO("image draw: cache miss, cached to an empty entry"); + } + +#else + cached_src = &cache_temp; +#endif + /*Open the image and measure the time to open*/ + uint32_t t_start; + t_start = lv_tick_get(); + cached_src->dec_dsc.time_to_open = 0; + lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color); + if(open_res == LV_RES_INV) { + LV_LOG_WARN("Image draw cannot open the image resource"); + lv_img_decoder_close(&cached_src->dec_dsc); + _lv_memset_00(&cached_src->dec_dsc, sizeof(lv_img_decoder_dsc_t)); + _lv_memset_00(cached_src, sizeof(lv_img_cache_entry_t)); + cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its use */ + return NULL; + } + + cached_src->life = 0; + + /*If `time_to_open` was not set in the open function set it here*/ + if(cached_src->dec_dsc.time_to_open == 0) { + cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start); + } + + if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1; + return cached_src; } @@ -157,6 +163,10 @@ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) */ void lv_img_cache_set_size(uint16_t new_entry_cnt) { +#if LV_IMG_CACHE_DEF_SIZE == 0 + LV_UNUSED(new_entry_cnt); + LV_LOG_WARN("Can't change cache size because it's disabled by LV_IMG_CACHE_DEF_SIZE = 0"); +#else if(LV_GC_ROOT(_lv_img_cache_array) != NULL) { /*Clean the cache before free it*/ lv_img_cache_invalidate_src(NULL); @@ -178,6 +188,7 @@ void lv_img_cache_set_size(uint16_t new_entry_cnt) _lv_memset_00(&LV_GC_ROOT(_lv_img_cache_array)[i].dec_dsc, sizeof(lv_img_decoder_dsc_t)); _lv_memset_00(&LV_GC_ROOT(_lv_img_cache_array)[i], sizeof(lv_img_cache_entry_t)); } +#endif } /** @@ -187,7 +198,7 @@ void lv_img_cache_set_size(uint16_t new_entry_cnt) */ void lv_img_cache_invalidate_src(const void * src) { - +#if LV_IMG_CACHE_DEF_SIZE lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array); uint16_t i; @@ -201,6 +212,7 @@ void lv_img_cache_invalidate_src(const void * src) _lv_memset_00(&cache[i], sizeof(lv_img_cache_entry_t)); } } +#endif } /********************** diff --git a/src/lv_gpu/lv_gpu_nxp_pxp.c b/src/lv_gpu/lv_gpu_nxp_pxp.c index d8ea7532a..ccb720297 100644 --- a/src/lv_gpu/lv_gpu_nxp_pxp.c +++ b/src/lv_gpu/lv_gpu_nxp_pxp.c @@ -56,7 +56,7 @@ #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565 -#elif +#else #error Only 16bit color depth is supported. Set LV_COLOR_DEPTH to 16. #endif diff --git a/src/lv_hal/lv_hal_disp.h b/src/lv_hal/lv_hal_disp.h index 62854d727..5098e376a 100644 --- a/src/lv_hal/lv_hal_disp.h +++ b/src/lv_hal/lv_hal_disp.h @@ -155,6 +155,9 @@ typedef struct _disp_t { struct _lv_obj_t ** screens; /**< Array of screen objects. `NULL` terminated*/ struct _lv_obj_t * act_scr; /**< Currently active screen on this display */ struct _lv_obj_t * prev_scr; /**< Previous screen. Used during screen animations */ +#if LV_USE_ANIMATION + struct _lv_obj_t * scr_to_load; /**< The screen prepared to load in lv_scr_load_anim*/ +#endif struct _lv_obj_t * top_layer; /**< @see lv_disp_get_layer_top */ struct _lv_obj_t * sys_layer; /**< @see lv_disp_get_layer_sys */ uint32_t screen_cnt; diff --git a/src/lv_misc/lv_txt.c b/src/lv_misc/lv_txt.c index 5d05c714e..619545367 100644 --- a/src/lv_misc/lv_txt.c +++ b/src/lv_misc/lv_txt.c @@ -8,6 +8,7 @@ *********************/ #include #include "lv_txt.h" +#include "lv_txt_ap.h" #include "lv_math.h" #include "lv_log.h" #include "lv_debug.h" @@ -793,7 +794,7 @@ static uint8_t lv_txt_iso8859_1_size(const char * str) */ static uint32_t lv_txt_unicode_to_iso8859_1(uint32_t letter_uni) { - if(letter_uni < 128) + if(letter_uni < 256) return letter_uni; else return ' '; diff --git a/src/lv_misc/lv_txt.h b/src/lv_misc/lv_txt.h index a5e78d9da..3f1f858e9 100644 --- a/src/lv_misc/lv_txt.h +++ b/src/lv_misc/lv_txt.h @@ -16,6 +16,7 @@ extern "C" { #include "../lv_conf_internal.h" #include +#include #include "lv_area.h" #include "lv_area.h" #include "../lv_font/lv_font.h" diff --git a/src/lv_misc/lv_txt_ap.c b/src/lv_misc/lv_txt_ap.c index 1a868ee2d..1bf68207d 100644 --- a/src/lv_misc/lv_txt_ap.c +++ b/src/lv_misc/lv_txt_ap.c @@ -69,7 +69,7 @@ const ap_chars_map_t ap_chars_map[] = { {36, 0xFEE6, 1, 2, -1, {1, 1}}, // ن {38, 0xFEEE, -1, 0, -1, {1, 0}}, // و {37, 0xFEEA, 1, 2, -1, {1, 1}}, // ه - {39, 0xFBFD, 1, 2, -1, {1, 1}}, // ي + {39, 0xFEF0, 0, 0, -1, {1, 0}}, // ى {40, 0xFEF2, 1, 2, -1, {1, 1}}, // ي {170, 0xFBFD, 1, 2, -1, {1, 1}}, // ی {7, 0xFE94, 1, 2, -1, {1, 0}}, // ة diff --git a/src/lv_themes/lv_theme_material.c b/src/lv_themes/lv_theme_material.c new file mode 100644 index 000000000..43c3d4927 --- /dev/null +++ b/src/lv_themes/lv_theme_material.c @@ -0,0 +1,1398 @@ +/** + * @file lv_theme_material.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../../lvgl.h" /*To see all the widgets*/ + +#if LV_USE_THEME_MATERIAL + +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) + #include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ + +/*SCREEN*/ + +#define COLOR_SCR (IS_LIGHT ? lv_color_hex(0xeaeff3) : lv_color_hex(0x444b5a)) +#define COLOR_SCR_TEXT (IS_LIGHT ? lv_color_hex(0x3b3e42) : lv_color_hex(0xe7e9ec)) + +/*BUTTON*/ +#define COLOR_BTN (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0x586273)) +#define COLOR_BTN_PR (IS_LIGHT ? lv_color_mix(theme.color_primary, COLOR_BTN, LV_OPA_20) : lv_color_mix(theme.color_primary, COLOR_BTN, LV_OPA_30)) + +#define COLOR_BTN_CHK (theme.color_primary) +#define COLOR_BTN_CHK_PR (lv_color_darken(theme.color_primary, LV_OPA_30)) +#define COLOR_BTN_DIS (IS_LIGHT ? lv_color_hex3(0xccc) : lv_color_hex3(0x888)) + +#define COLOR_BTN_BORDER theme.color_primary +#define COLOR_BTN_BORDER_PR theme.color_primary +#define COLOR_BTN_BORDER_CHK theme.color_primary +#define COLOR_BTN_BORDER_CHK_PR theme.color_primary +#define COLOR_BTN_BORDER_INA (IS_LIGHT ? lv_color_hex3(0x888) : lv_color_hex(0x404040)) + +/*BACKGROUND*/ +#define COLOR_BG (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0x586273)) +#define COLOR_BG_PR (IS_LIGHT ? lv_color_hex(0xeeeeee) : lv_color_hex(0x494f57)) +#define COLOR_BG_CHK theme.color_primary +#define COLOR_BG_PR_CHK lv_color_darken(theme.color_primary, LV_OPA_20) +#define COLOR_BG_DIS COLOR_BG + +#define COLOR_BG_BORDER (IS_LIGHT ? lv_color_hex(0xd6dde3) : lv_color_hex(0x808a97)) /*dfe7ed*/ +#define COLOR_BG_BORDER_PR (IS_LIGHT ? lv_color_hex3(0xccc) : lv_color_hex(0x5f656e)) +#define COLOR_BG_BORDER_CHK (IS_LIGHT ? lv_color_hex(0x3b3e42) : lv_color_hex(0x5f656e)) +#define COLOR_BG_BORDER_CHK_PR (IS_LIGHT ? lv_color_hex(0x3b3e42) : lv_color_hex(0x5f656e)) +#define COLOR_BG_BORDER_DIS (IS_LIGHT ? lv_color_hex(0xd6dde3) : lv_color_hex(0x5f656e)) + +#define COLOR_BG_TEXT (IS_LIGHT ? lv_color_hex(0x3b3e42) : lv_color_hex(0xffffff)) +#define COLOR_BG_TEXT_PR (IS_LIGHT ? lv_color_hex(0x3b3e42) : lv_color_hex(0xffffff)) +#define COLOR_BG_TEXT_CHK (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0xffffff)) +#define COLOR_BG_TEXT_CHK_PR (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0xffffff)) +#define COLOR_BG_TEXT_DIS (IS_LIGHT ? lv_color_hex3(0xaaa) : lv_color_hex3(0x999)) + +/*SECONDARY BACKGROUND*/ +#define COLOR_BG_SEC (IS_LIGHT ? lv_color_hex(0xd4d7d9) : lv_color_hex(0x45494d)) +#define COLOR_BG_SEC_BORDER (IS_LIGHT ? lv_color_hex(0xdfe7ed) : lv_color_hex(0x404040)) +#define COLOR_BG_SEC_TEXT (IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xa5a8ad)) +#define COLOR_BG_SEC_TEXT_DIS (IS_LIGHT ? lv_color_hex(0xaaaaaa) : lv_color_hex(0xa5a8ad)) + +#define TRANSITION_TIME 0/*((theme.flags & LV_THEME_MATERIAL_FLAG_NO_TRANSITION) ? 0 : 150)*/ +#define BORDER_WIDTH LV_DPX(2) +#define OUTLINE_WIDTH ((theme.flags & LV_THEME_MATERIAL_FLAG_NO_FOCUS) ? 0 : LV_DPX(2)) +#define IS_LIGHT (theme.flags & LV_THEME_MATERIAL_FLAG_LIGHT) + +#define PAD_DEF (lv_disp_get_size_category(NULL) <= LV_DISP_SIZE_MEDIUM ? LV_DPX(15) : (LV_DPX(30))) + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_style_t scr; + lv_style_t bg; + lv_style_t bg_click; + lv_style_t bg_sec; + lv_style_t btn; + lv_style_t pad_inner; + lv_style_t pad_small; + +#if LV_USE_ARC + lv_style_t arc_indic; + lv_style_t arc_bg; + lv_style_t arc_knob; +#endif + +#if LV_USE_BAR + lv_style_t bar_bg; + lv_style_t bar_indic; +#endif + +#if LV_USE_CALENDAR + lv_style_t calendar_date_nums, calendar_header, calendar_daynames; +#endif + +#if LV_USE_CPICKER + lv_style_t cpicker_bg, cpicker_indic; +#endif + +#if LV_USE_CHART + lv_style_t chart_bg, chart_series_bg, chart_series; +#endif + +#if LV_USE_CHECKBOX + lv_style_t cb_bg, cb_bullet; +#endif + +#if LV_USE_DROPDOWN + lv_style_t ddlist_page, ddlist_sel; +#endif + +#if LV_USE_GAUGE + lv_style_t gauge_main, gauge_strong, gauge_needle; +#endif + +#if LV_USE_KEYBOARD + lv_style_t kb_bg; +#endif + +#if LV_USE_LED + lv_style_t led; +#endif + +#if LV_USE_LINEMETER + lv_style_t lmeter; +#endif + +#if LV_USE_LIST + lv_style_t list_bg, list_btn; +#endif + +#if LV_USE_MSGBOX + lv_style_t mbox_bg; +#endif + +#if LV_USE_PAGE + lv_style_t sb; +#if LV_USE_ANIMATION + lv_style_t edge_flash; +#endif +#endif + +#if LV_USE_ROLLER + lv_style_t roller_bg, roller_sel; +#endif + +#if LV_USE_SLIDER + lv_style_t slider_knob, slider_bg; +#endif + +#if LV_USE_SPINBOX + lv_style_t spinbox_cursor; +#endif + +#if LV_USE_SWITCH + lv_style_t sw_knob; +#endif + +#if LV_USE_TABLE + lv_style_t table_cell; +#endif + +#if LV_USE_TABVIEW || LV_USE_WIN + lv_style_t tabview_btns, tabview_btns_bg, tabview_indic, tabview_page_scrl; +#endif + +#if LV_USE_TEXTAREA + lv_style_t ta_cursor, ta_placeholder; +#endif + +} theme_styles_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name); +static void style_init_reset(lv_style_t * style); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_theme_t theme; +static theme_styles_t * styles; + +static bool inited; + +/********************** + * MACROS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void basic_init(void) +{ + style_init_reset(&styles->scr); + lv_style_set_bg_opa(&styles->scr, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->scr, LV_STATE_DEFAULT, COLOR_SCR); + lv_style_set_text_color(&styles->scr, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_value_color(&styles->scr, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_text_sel_color(&styles->scr, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_text_sel_bg_color(&styles->scr, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_value_font(&styles->scr, LV_STATE_DEFAULT, theme.font_normal); + + style_init_reset(&styles->bg); + lv_style_set_radius(&styles->bg, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_bg_opa(&styles->bg, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->bg, LV_STATE_DEFAULT, COLOR_BG); + lv_style_set_border_color(&styles->bg, LV_STATE_DEFAULT, COLOR_BG_BORDER); + if((theme.flags & LV_THEME_MATERIAL_FLAG_NO_FOCUS) == 0)lv_style_set_border_color(&styles->bg, LV_STATE_FOCUSED, + theme.color_primary); + lv_style_set_border_color(&styles->bg, LV_STATE_EDITED, theme.color_secondary); + lv_style_set_border_width(&styles->bg, LV_STATE_DEFAULT, BORDER_WIDTH); + lv_style_set_border_post(&styles->bg, LV_STATE_DEFAULT, true); + lv_style_set_text_color(&styles->bg, LV_STATE_DEFAULT, COLOR_BG_TEXT); + lv_style_set_value_font(&styles->bg, LV_STATE_DEFAULT, theme.font_normal); + lv_style_set_value_color(&styles->bg, LV_STATE_DEFAULT, COLOR_BG_TEXT); + lv_style_set_image_recolor(&styles->bg, LV_STATE_DEFAULT, COLOR_BG_TEXT); + lv_style_set_line_color(&styles->bg, LV_STATE_DEFAULT, COLOR_BG_TEXT); + lv_style_set_line_width(&styles->bg, LV_STATE_DEFAULT, 1); + lv_style_set_pad_left(&styles->bg, LV_STATE_DEFAULT, PAD_DEF + BORDER_WIDTH); + lv_style_set_pad_right(&styles->bg, LV_STATE_DEFAULT, PAD_DEF + BORDER_WIDTH); + lv_style_set_pad_top(&styles->bg, LV_STATE_DEFAULT, PAD_DEF + BORDER_WIDTH); + lv_style_set_pad_bottom(&styles->bg, LV_STATE_DEFAULT, PAD_DEF + BORDER_WIDTH); + lv_style_set_pad_inner(&styles->bg, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_transition_time(&styles->bg, LV_STATE_DEFAULT, TRANSITION_TIME); + lv_style_set_transition_prop_6(&styles->bg, LV_STATE_DEFAULT, LV_STYLE_BORDER_COLOR); + + style_init_reset(&styles->bg_sec); + lv_style_copy(&styles->bg_sec, &styles->bg); + lv_style_set_bg_color(&styles->bg_sec, LV_STATE_DEFAULT, COLOR_BG_SEC); + lv_style_set_border_color(&styles->bg_sec, LV_STATE_DEFAULT, COLOR_BG_SEC_BORDER); + lv_style_set_text_color(&styles->bg_sec, LV_STATE_DEFAULT, COLOR_BG_SEC_TEXT); + lv_style_set_value_color(&styles->bg_sec, LV_STATE_DEFAULT, COLOR_BG_SEC_TEXT); + lv_style_set_image_recolor(&styles->bg_sec, LV_STATE_DEFAULT, COLOR_BG_SEC_TEXT); + lv_style_set_line_color(&styles->bg_sec, LV_STATE_DEFAULT, COLOR_BG_SEC_TEXT); + + style_init_reset(&styles->bg_click); + lv_style_set_bg_color(&styles->bg_click, LV_STATE_PRESSED, COLOR_BG_PR); + lv_style_set_bg_color(&styles->bg_click, LV_STATE_CHECKED, COLOR_BG_CHK); + lv_style_set_bg_color(&styles->bg_click, LV_STATE_PRESSED | LV_STATE_CHECKED, COLOR_BG_PR_CHK); + lv_style_set_bg_color(&styles->bg_click, LV_STATE_DISABLED, COLOR_BG_DIS); + lv_style_set_border_width(&styles->bg_click, LV_STATE_CHECKED, 0); + lv_style_set_border_color(&styles->bg_click, LV_STATE_FOCUSED | LV_STATE_PRESSED, lv_color_darken(theme.color_primary, + LV_OPA_20)); + lv_style_set_border_color(&styles->bg_click, LV_STATE_PRESSED, COLOR_BG_BORDER_PR); + lv_style_set_border_color(&styles->bg_click, LV_STATE_CHECKED, COLOR_BG_BORDER_CHK); + lv_style_set_border_color(&styles->bg_click, LV_STATE_PRESSED | LV_STATE_CHECKED, COLOR_BG_BORDER_CHK_PR); + lv_style_set_border_color(&styles->bg_click, LV_STATE_DISABLED, COLOR_BG_BORDER_DIS); + lv_style_set_text_color(&styles->bg_click, LV_STATE_PRESSED, COLOR_BG_TEXT_PR); + lv_style_set_text_color(&styles->bg_click, LV_STATE_CHECKED, COLOR_BG_TEXT_CHK); + lv_style_set_text_color(&styles->bg_click, LV_STATE_PRESSED | LV_STATE_CHECKED, COLOR_BG_TEXT_CHK_PR); + lv_style_set_text_color(&styles->bg_click, LV_STATE_DISABLED, COLOR_BG_TEXT_DIS); + lv_style_set_image_recolor(&styles->bg_click, LV_STATE_PRESSED, COLOR_BG_TEXT_PR); + lv_style_set_image_recolor(&styles->bg_click, LV_STATE_CHECKED, COLOR_BG_TEXT_CHK); + lv_style_set_image_recolor(&styles->bg_click, LV_STATE_PRESSED | LV_STATE_CHECKED, COLOR_BG_TEXT_CHK_PR); + lv_style_set_image_recolor(&styles->bg_click, LV_STATE_DISABLED, COLOR_BG_TEXT_DIS); + lv_style_set_transition_prop_5(&styles->bg_click, LV_STATE_DEFAULT, LV_STYLE_BG_COLOR); + + style_init_reset(&styles->btn); + lv_style_set_radius(&styles->btn, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_bg_opa(&styles->btn, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->btn, LV_STATE_DEFAULT, COLOR_BTN); + lv_style_set_bg_color(&styles->btn, LV_STATE_PRESSED, COLOR_BTN_PR); + lv_style_set_bg_color(&styles->btn, LV_STATE_CHECKED, COLOR_BTN_CHK); + lv_style_set_bg_color(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, COLOR_BTN_CHK_PR); + lv_style_set_bg_color(&styles->btn, LV_STATE_DISABLED, COLOR_BTN); + lv_style_set_bg_color(&styles->btn, LV_STATE_DISABLED | LV_STATE_CHECKED, COLOR_BTN_DIS); + lv_style_set_border_color(&styles->btn, LV_STATE_DEFAULT, COLOR_BTN_BORDER); + lv_style_set_border_color(&styles->btn, LV_STATE_PRESSED, COLOR_BTN_BORDER_PR); + lv_style_set_border_color(&styles->btn, LV_STATE_DISABLED, COLOR_BTN_BORDER_INA); + lv_style_set_border_width(&styles->btn, LV_STATE_DEFAULT, BORDER_WIDTH); + lv_style_set_border_opa(&styles->btn, LV_STATE_CHECKED, LV_OPA_TRANSP); + + lv_style_set_text_color(&styles->btn, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); + lv_style_set_text_color(&styles->btn, LV_STATE_PRESSED, IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); + lv_style_set_text_color(&styles->btn, LV_STATE_CHECKED, lv_color_hex(0xffffff)); + lv_style_set_text_color(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_hex(0xffffff)); + lv_style_set_text_color(&styles->btn, LV_STATE_DISABLED, IS_LIGHT ? lv_color_hex(0x888888) : lv_color_hex(0x888888)); + + lv_style_set_image_recolor(&styles->btn, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); + lv_style_set_image_recolor(&styles->btn, LV_STATE_PRESSED, IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); + lv_style_set_image_recolor(&styles->btn, LV_STATE_PRESSED, lv_color_hex(0xffffff)); + lv_style_set_image_recolor(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_hex(0xffffff)); + lv_style_set_image_recolor(&styles->btn, LV_STATE_DISABLED, IS_LIGHT ? lv_color_hex(0x888888) : lv_color_hex(0x888888)); + + lv_style_set_value_color(&styles->btn, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); + lv_style_set_value_color(&styles->btn, LV_STATE_PRESSED, IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); + lv_style_set_value_color(&styles->btn, LV_STATE_CHECKED, lv_color_hex(0xffffff)); + lv_style_set_value_color(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_hex(0xffffff)); + lv_style_set_value_color(&styles->btn, LV_STATE_DISABLED, IS_LIGHT ? lv_color_hex(0x888888) : lv_color_hex(0x888888)); + + lv_style_set_pad_left(&styles->btn, LV_STATE_DEFAULT, LV_DPX(40)); + lv_style_set_pad_right(&styles->btn, LV_STATE_DEFAULT, LV_DPX(40)); + lv_style_set_pad_top(&styles->btn, LV_STATE_DEFAULT, LV_DPX(15)); + lv_style_set_pad_bottom(&styles->btn, LV_STATE_DEFAULT, LV_DPX(15)); + lv_style_set_pad_inner(&styles->btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_outline_width(&styles->btn, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_outline_opa(&styles->btn, LV_STATE_DEFAULT, LV_OPA_0); + lv_style_set_outline_opa(&styles->btn, LV_STATE_FOCUSED, LV_OPA_50); + lv_style_set_outline_color(&styles->btn, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_outline_color(&styles->btn, LV_STATE_EDITED, theme.color_secondary); + lv_style_set_transition_time(&styles->btn, LV_STATE_DEFAULT, TRANSITION_TIME); + lv_style_set_transition_prop_4(&styles->btn, LV_STATE_DEFAULT, LV_STYLE_BORDER_OPA); + lv_style_set_transition_prop_5(&styles->btn, LV_STATE_DEFAULT, LV_STYLE_BG_COLOR); + lv_style_set_transition_prop_6(&styles->btn, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); + lv_style_set_transition_delay(&styles->btn, LV_STATE_DEFAULT, TRANSITION_TIME); + lv_style_set_transition_delay(&styles->btn, LV_STATE_PRESSED, 0); + + style_init_reset(&styles->pad_inner); + + lv_style_set_pad_inner(&styles->pad_inner, LV_STATE_DEFAULT, + lv_disp_get_size_category(NULL) <= LV_DISP_SIZE_MEDIUM ? LV_DPX(20) : LV_DPX(40)); + + style_init_reset(&styles->pad_small); + lv_style_int_t pad_small_value = lv_disp_get_size_category(NULL) <= LV_DISP_SIZE_MEDIUM ? LV_DPX(10) : LV_DPX(20); + lv_style_set_pad_left(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_right(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_top(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_bottom(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_inner(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); +} + +static void cont_init(void) +{ +#if LV_USE_CONT != 0 + +#endif +} + +static void btn_init(void) +{ +#if LV_USE_BTN != 0 + +#endif +} + +static void label_init(void) +{ +#if LV_USE_LABEL != 0 + +#endif +} + +static void bar_init(void) +{ +#if LV_USE_BAR + style_init_reset(&styles->bar_bg); + lv_style_set_radius(&styles->bar_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_bg_opa(&styles->bar_bg, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->bar_bg, LV_STATE_DEFAULT, COLOR_BG_SEC); + lv_style_set_value_color(&styles->bar_bg, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE); + lv_style_set_outline_color(&styles->bar_bg, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_outline_color(&styles->bar_bg, LV_STATE_EDITED, theme.color_secondary); + lv_style_set_outline_opa(&styles->bar_bg, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_style_set_outline_opa(&styles->bar_bg, LV_STATE_FOCUSED, LV_OPA_50); + lv_style_set_outline_width(&styles->bar_bg, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_transition_time(&styles->bar_bg, LV_STATE_DEFAULT, TRANSITION_TIME); + lv_style_set_transition_prop_6(&styles->bar_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); + + style_init_reset(&styles->bar_indic); + lv_style_set_bg_opa(&styles->bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_radius(&styles->bar_indic, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_bg_color(&styles->bar_indic, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_bg_color(&styles->bar_indic, LV_STATE_DISABLED, lv_color_hex3(0x888)); + lv_style_set_value_color(&styles->bar_indic, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x41404f) : LV_COLOR_WHITE); +#endif +} + +static void img_init(void) +{ +#if LV_USE_IMG != 0 + +#endif +} + +static void line_init(void) +{ +#if LV_USE_LINE != 0 + +#endif +} + +static void led_init(void) +{ +#if LV_USE_LED != 0 + style_init_reset(&styles->led); + lv_style_set_bg_opa(&styles->led, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->led, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_border_width(&styles->led, LV_STATE_DEFAULT, 2); + lv_style_set_border_opa(&styles->led, LV_STATE_DEFAULT, LV_OPA_50); + lv_style_set_border_color(&styles->led, LV_STATE_DEFAULT, lv_color_lighten(theme.color_primary, LV_OPA_30)); + lv_style_set_radius(&styles->led, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_shadow_width(&styles->led, LV_STATE_DEFAULT, LV_DPX(15)); + lv_style_set_shadow_color(&styles->led, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_shadow_spread(&styles->led, LV_STATE_DEFAULT, LV_DPX(5)); +#endif +} + +static void slider_init(void) +{ +#if LV_USE_SLIDER != 0 + style_init_reset(&styles->slider_knob); + lv_style_set_bg_opa(&styles->slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->slider_knob, LV_STATE_DEFAULT, IS_LIGHT ? theme.color_primary : LV_COLOR_WHITE); + lv_style_set_value_color(&styles->slider_knob, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE); + lv_style_set_radius(&styles->slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_left(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_right(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_top(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_bottom(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); + + style_init_reset(&styles->slider_bg); + lv_style_set_margin_left(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_margin_right(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_margin_top(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_margin_bottom(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); + +#endif +} + +static void switch_init(void) +{ +#if LV_USE_SWITCH != 0 + style_init_reset(&styles->sw_knob); + lv_style_set_bg_opa(&styles->sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->sw_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_radius(&styles->sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_top(&styles->sw_knob, LV_STATE_DEFAULT, - LV_DPX(4)); + lv_style_set_pad_bottom(&styles->sw_knob, LV_STATE_DEFAULT, - LV_DPX(4)); + lv_style_set_pad_left(&styles->sw_knob, LV_STATE_DEFAULT, - LV_DPX(4)); + lv_style_set_pad_right(&styles->sw_knob, LV_STATE_DEFAULT, - LV_DPX(4)); +#endif +} + +static void linemeter_init(void) +{ +#if LV_USE_LINEMETER != 0 + style_init_reset(&styles->lmeter); + lv_style_set_radius(&styles->lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_left(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_right(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_top(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_inner(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(30)); + lv_style_set_scale_width(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(25)); + + lv_style_set_line_color(&styles->lmeter, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_scale_grad_color(&styles->lmeter, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_scale_end_color(&styles->lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888)); + lv_style_set_line_width(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_scale_end_line_width(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(7)); +#endif +} + +static void gauge_init(void) +{ +#if LV_USE_GAUGE != 0 + style_init_reset(&styles->gauge_main); + lv_style_set_line_color(&styles->gauge_main, LV_STATE_DEFAULT, lv_color_hex3(0x888)); + lv_style_set_scale_grad_color(&styles->gauge_main, LV_STATE_DEFAULT, lv_color_hex3(0x888)); + lv_style_set_scale_end_color(&styles->gauge_main, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_line_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_scale_end_line_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_scale_end_border_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_pad_left(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_right(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_top(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_inner(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_scale_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(15)); + lv_style_set_radius(&styles->gauge_main, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + + style_init_reset(&styles->gauge_strong); + lv_style_set_line_color(&styles->gauge_strong, LV_STATE_DEFAULT, lv_color_hex3(0x888)); + lv_style_set_scale_grad_color(&styles->gauge_strong, LV_STATE_DEFAULT, lv_color_hex3(0x888)); + lv_style_set_scale_end_color(&styles->gauge_strong, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_line_width(&styles->gauge_strong, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_scale_end_line_width(&styles->gauge_strong, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_scale_width(&styles->gauge_strong, LV_STATE_DEFAULT, LV_DPX(25)); + + style_init_reset(&styles->gauge_needle); + lv_style_set_line_color(&styles->gauge_needle, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x464b5b) : LV_COLOR_WHITE); + lv_style_set_line_width(&styles->gauge_needle, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_bg_opa(&styles->gauge_needle, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->gauge_needle, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x464b5b) : LV_COLOR_WHITE); + lv_style_set_radius(&styles->gauge_needle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_size(&styles->gauge_needle, LV_STATE_DEFAULT, LV_DPX(30)); + lv_style_set_pad_inner(&styles->gauge_needle, LV_STATE_DEFAULT, LV_DPX(10)); +#endif +} + +static void arc_init(void) +{ +#if LV_USE_ARC != 0 + style_init_reset(&styles->arc_indic); + lv_style_set_line_color(&styles->arc_indic, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_line_width(&styles->arc_indic, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_line_rounded(&styles->arc_indic, LV_STATE_DEFAULT, true); + + style_init_reset(&styles->arc_bg); + lv_style_set_line_color(&styles->arc_bg, LV_STATE_DEFAULT, COLOR_BG_SEC); + lv_style_set_line_width(&styles->arc_bg, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_line_rounded(&styles->arc_bg, LV_STATE_DEFAULT, true); + + style_init_reset(&styles->arc_knob); + lv_style_set_radius(&styles->arc_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_top(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); + lv_style_set_pad_bottom(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); + lv_style_set_pad_left(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); + lv_style_set_pad_right(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); + +#endif +} + +static void spinner_init(void) +{ +#if LV_USE_SPINNER != 0 +#endif +} + +static void chart_init(void) +{ +#if LV_USE_CHART + style_init_reset(&styles->chart_bg); + lv_style_set_text_color(&styles->chart_bg, LV_STATE_DEFAULT, IS_LIGHT ? COLOR_BG_TEXT_DIS : lv_color_hex(0xa1adbd)); + + style_init_reset(&styles->chart_series_bg); + lv_style_set_line_width(&styles->chart_series_bg, LV_STATE_DEFAULT, LV_DPX(1)); + lv_style_set_line_dash_width(&styles->chart_series_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_line_dash_gap(&styles->chart_series_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_line_color(&styles->chart_series_bg, LV_STATE_DEFAULT, COLOR_BG_BORDER); + + style_init_reset(&styles->chart_series); + lv_style_set_line_width(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_size(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_pad_inner(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(2)); /*Space between columns*/ + lv_style_set_radius(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(1)); + +#endif +} + +static void calendar_init(void) +{ +#if LV_USE_CALENDAR + + style_init_reset(&styles->calendar_header); + lv_style_set_pad_top(&styles->calendar_header, LV_STATE_DEFAULT, 0); + lv_style_set_pad_left(&styles->calendar_header, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_right(&styles->calendar_header, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_bottom(&styles->calendar_header, LV_STATE_DEFAULT, 0); + lv_style_set_margin_top(&styles->calendar_header, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_margin_bottom(&styles->calendar_header, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_text_color(&styles->calendar_header, LV_STATE_PRESSED, IS_LIGHT ? lv_color_hex(0x888888) : LV_COLOR_WHITE); + + style_init_reset(&styles->calendar_daynames); + lv_style_set_text_color(&styles->calendar_daynames, LV_STATE_DEFAULT, + IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex3(0xeee)); + lv_style_set_pad_left(&styles->calendar_daynames, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_right(&styles->calendar_daynames, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_bottom(&styles->calendar_daynames, LV_STATE_DEFAULT, PAD_DEF); + + style_init_reset(&styles->calendar_date_nums); + lv_style_set_radius(&styles->calendar_date_nums, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_text_color(&styles->calendar_date_nums, LV_STATE_CHECKED, + IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE); + lv_style_set_text_color(&styles->calendar_date_nums, LV_STATE_DISABLED, LV_COLOR_GRAY); + lv_style_set_bg_opa(&styles->calendar_date_nums, LV_STATE_CHECKED, IS_LIGHT ? LV_OPA_20 : LV_OPA_40); + lv_style_set_bg_opa(&styles->calendar_date_nums, LV_STATE_PRESSED, LV_OPA_20); + lv_style_set_bg_opa(&styles->calendar_date_nums, LV_STATE_FOCUSED, LV_OPA_COVER); + lv_style_set_text_color(&styles->calendar_date_nums, LV_STATE_FOCUSED, LV_COLOR_WHITE); + lv_style_set_bg_color(&styles->calendar_date_nums, LV_STATE_FOCUSED, theme.color_primary); + lv_style_set_bg_color(&styles->calendar_date_nums, LV_STATE_DEFAULT, + IS_LIGHT ? lv_color_hex(0x666666) : LV_COLOR_WHITE); + lv_style_set_bg_color(&styles->calendar_date_nums, LV_STATE_CHECKED, theme.color_primary); + lv_style_set_border_width(&styles->calendar_date_nums, LV_STATE_CHECKED, 2); + lv_style_set_border_side(&styles->calendar_date_nums, LV_STATE_CHECKED, LV_BORDER_SIDE_LEFT); + lv_style_set_border_color(&styles->calendar_date_nums, LV_STATE_CHECKED, theme.color_primary); + lv_style_set_pad_inner(&styles->calendar_date_nums, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_pad_left(&styles->calendar_date_nums, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_right(&styles->calendar_date_nums, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_bottom(&styles->calendar_date_nums, LV_STATE_DEFAULT, PAD_DEF); +#endif +} + +static void cpicker_init(void) +{ +#if LV_USE_CPICKER + style_init_reset(&styles->cpicker_bg); + lv_style_set_scale_width(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_DPX(30)); + lv_style_set_bg_opa(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->cpicker_bg, LV_STATE_DEFAULT, COLOR_SCR); + lv_style_set_pad_inner(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_radius(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + + style_init_reset(&styles->cpicker_indic); + lv_style_set_radius(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_bg_color(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_bg_opa(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_border_width(&styles->cpicker_indic, LV_STATE_DEFAULT, 2); + lv_style_set_border_color(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_style_set_border_color(&styles->cpicker_indic, LV_STATE_FOCUSED, theme.color_primary); + lv_style_set_border_color(&styles->cpicker_indic, LV_STATE_EDITED, theme.color_secondary); + lv_style_set_pad_left(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); + lv_style_set_pad_right(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); + lv_style_set_pad_top(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); + lv_style_set_pad_bottom(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); +#endif +} + +static void checkbox_init(void) +{ +#if LV_USE_CHECKBOX != 0 + style_init_reset(&styles->cb_bg); + lv_style_set_radius(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_pad_inner(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_outline_color(&styles->cb_bg, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_outline_opa(&styles->cb_bg, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_style_set_outline_opa(&styles->cb_bg, LV_STATE_FOCUSED, LV_OPA_50); + lv_style_set_outline_width(&styles->cb_bg, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_outline_pad(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_transition_time(&styles->cb_bg, LV_STATE_DEFAULT, TRANSITION_TIME); + lv_style_set_transition_prop_6(&styles->cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); + + style_init_reset(&styles->cb_bullet); + lv_style_set_outline_opa(&styles->cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP); + lv_style_set_radius(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_pattern_image(&styles->cb_bullet, LV_STATE_CHECKED, LV_SYMBOL_OK); + lv_style_set_pattern_recolor(&styles->cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_pattern_opa(&styles->cb_bullet, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_style_set_pattern_opa(&styles->cb_bullet, LV_STATE_CHECKED, LV_OPA_COVER); + lv_style_set_transition_prop_3(&styles->cb_bullet, LV_STATE_DEFAULT, LV_STYLE_PATTERN_OPA); + lv_style_set_text_font(&styles->cb_bullet, LV_STATE_CHECKED, theme.font_small); + lv_style_set_pad_left(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_pad_right(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_pad_top(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_pad_bottom(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); +#endif +} + +static void btnmatrix_init(void) +{ +} + +static void keyboard_init(void) +{ +#if LV_USE_KEYBOARD + style_init_reset(&styles->kb_bg); + lv_style_set_radius(&styles->kb_bg, LV_STATE_DEFAULT, 0); + lv_style_set_border_width(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_border_side(&styles->kb_bg, LV_STATE_DEFAULT, LV_BORDER_SIDE_TOP); + lv_style_set_border_color(&styles->kb_bg, LV_STATE_DEFAULT, IS_LIGHT ? COLOR_BG_TEXT : LV_COLOR_BLACK); + lv_style_set_border_color(&styles->kb_bg, LV_STATE_EDITED, theme.color_secondary); + lv_style_set_pad_left(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_pad_right(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_pad_top(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_pad_bottom(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_pad_inner(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(3)); +#endif +} + +static void msgbox_init(void) +{ +#if LV_USE_MSGBOX + style_init_reset(&styles->mbox_bg); + lv_style_set_shadow_width(&styles->mbox_bg, LV_STATE_DEFAULT, LV_DPX(50)); + lv_style_set_shadow_color(&styles->mbox_bg, LV_STATE_DEFAULT, IS_LIGHT ? LV_COLOR_SILVER : lv_color_hex3(0x999)); + +#endif +} + +static void page_init(void) +{ +#if LV_USE_PAGE + style_init_reset(&styles->sb); + lv_style_set_bg_opa(&styles->sb, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->sb, LV_STATE_DEFAULT, (IS_LIGHT ? lv_color_hex(0xcccfd1) : lv_color_hex(0x777f85))); + lv_style_set_radius(&styles->sb, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_size(&styles->sb, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_right(&styles->sb, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_bottom(&styles->sb, LV_STATE_DEFAULT, LV_DPX(7)); + +#if LV_USE_ANIMATION + style_init_reset(&styles->edge_flash); + lv_style_set_bg_opa(&styles->edge_flash, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->edge_flash, LV_STATE_DEFAULT, lv_color_hex3(0x888)); +#endif +#endif +} + +static void textarea_init(void) +{ +#if LV_USE_TEXTAREA + style_init_reset(&styles->ta_cursor); + lv_style_set_border_color(&styles->ta_cursor, LV_STATE_DEFAULT, COLOR_BG_SEC_TEXT); + lv_style_set_border_width(&styles->ta_cursor, LV_STATE_DEFAULT, LV_DPX(2)); + lv_style_set_pad_left(&styles->ta_cursor, LV_STATE_DEFAULT, LV_DPX(1)); + lv_style_set_border_side(&styles->ta_cursor, LV_STATE_DEFAULT, LV_BORDER_SIDE_LEFT); + + style_init_reset(&styles->ta_placeholder); + lv_style_set_text_color(&styles->ta_placeholder, LV_STATE_DEFAULT, + IS_LIGHT ? COLOR_BG_TEXT_DIS : lv_color_hex(0xa1adbd)); +#endif +} + +static void spinbox_init(void) +{ +#if LV_USE_SPINBOX + + style_init_reset(&styles->spinbox_cursor); + lv_style_set_bg_opa(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->spinbox_cursor, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_text_color(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_pad_top(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_DPX(100)); + lv_style_set_pad_bottom(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_DPX(100)); + +#endif +} + +static void list_init(void) +{ +#if LV_USE_LIST != 0 + style_init_reset(&styles->list_bg); + lv_style_set_clip_corner(&styles->list_bg, LV_STATE_DEFAULT, true); + lv_style_set_pad_left(&styles->list_bg, LV_STATE_DEFAULT, 0); + lv_style_set_pad_right(&styles->list_bg, LV_STATE_DEFAULT, 0); + lv_style_set_pad_top(&styles->list_bg, LV_STATE_DEFAULT, 0); + lv_style_set_pad_bottom(&styles->list_bg, LV_STATE_DEFAULT, 0); + lv_style_set_pad_inner(&styles->list_bg, LV_STATE_DEFAULT, 0); + + style_init_reset(&styles->list_btn); + lv_style_set_bg_opa(&styles->list_btn, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->list_btn, LV_STATE_DEFAULT, COLOR_BG); + lv_style_set_bg_color(&styles->list_btn, LV_STATE_PRESSED, COLOR_BG_PR); + lv_style_set_bg_color(&styles->list_btn, LV_STATE_DISABLED, COLOR_BG_DIS); + lv_style_set_bg_color(&styles->list_btn, LV_STATE_CHECKED, COLOR_BG_CHK); + lv_style_set_bg_color(&styles->list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, COLOR_BG_PR_CHK); + + lv_style_set_text_color(&styles->list_btn, LV_STATE_DEFAULT, COLOR_BG_TEXT); + lv_style_set_text_color(&styles->list_btn, LV_STATE_CHECKED, COLOR_BG_TEXT_CHK); + lv_style_set_text_color(&styles->list_btn, LV_STATE_DISABLED, COLOR_BG_TEXT_DIS); + + lv_style_set_image_recolor(&styles->list_btn, LV_STATE_DEFAULT, COLOR_BG_TEXT); + lv_style_set_image_recolor(&styles->list_btn, LV_STATE_CHECKED, COLOR_BG_TEXT_CHK); + lv_style_set_image_recolor(&styles->list_btn, LV_STATE_DISABLED, COLOR_BG_TEXT_DIS); + + lv_style_set_border_side(&styles->list_btn, LV_STATE_DEFAULT, LV_BORDER_SIDE_BOTTOM); + lv_style_set_border_color(&styles->list_btn, LV_STATE_DEFAULT, COLOR_BG_BORDER); + lv_style_set_border_color(&styles->list_btn, LV_STATE_FOCUSED, theme.color_primary); + lv_style_set_border_width(&styles->list_btn, LV_STATE_DEFAULT, 1); + + lv_style_set_outline_color(&styles->list_btn, LV_STATE_FOCUSED, theme.color_secondary); + lv_style_set_outline_width(&styles->list_btn, LV_STATE_FOCUSED, OUTLINE_WIDTH); + lv_style_set_outline_pad(&styles->list_btn, LV_STATE_FOCUSED, -BORDER_WIDTH); + + lv_style_set_pad_left(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_right(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_top(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_bottom(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_inner(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); + + lv_style_set_transform_width(&styles->list_btn, LV_STATE_DEFAULT, - PAD_DEF); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_PRESSED, -BORDER_WIDTH); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_CHECKED, -BORDER_WIDTH); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_DISABLED, -BORDER_WIDTH); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_FOCUSED, - BORDER_WIDTH); + + lv_style_set_transition_time(&styles->list_btn, LV_STATE_DEFAULT, TRANSITION_TIME); + lv_style_set_transition_prop_6(&styles->list_btn, LV_STATE_DEFAULT, LV_STYLE_BG_COLOR); + lv_style_set_transition_prop_5(&styles->list_btn, LV_STATE_DEFAULT, LV_STYLE_TRANSFORM_WIDTH); +#endif +} + +static void ddlist_init(void) +{ +#if LV_USE_DROPDOWN != 0 + + style_init_reset(&styles->ddlist_page); + lv_style_set_text_line_space(&styles->ddlist_page, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_clip_corner(&styles->ddlist_page, LV_STATE_DEFAULT, true); + + style_init_reset(&styles->ddlist_sel); + lv_style_set_bg_opa(&styles->ddlist_sel, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->ddlist_sel, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_text_color(&styles->ddlist_sel, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex3(0xfff) : lv_color_hex3(0xfff)); + lv_style_set_bg_color(&styles->ddlist_sel, LV_STATE_PRESSED, COLOR_BG_PR); + lv_style_set_text_color(&styles->ddlist_sel, LV_STATE_PRESSED, COLOR_BG_TEXT_PR); +#endif +} + +static void roller_init(void) +{ +#if LV_USE_ROLLER != 0 + style_init_reset(&styles->roller_bg); + lv_style_set_text_line_space(&styles->roller_bg, LV_STATE_DEFAULT, LV_DPX(25)); + + style_init_reset(&styles->roller_sel); + lv_style_set_bg_opa(&styles->roller_sel, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->roller_sel, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_text_color(&styles->roller_sel, LV_STATE_DEFAULT, LV_COLOR_WHITE); +#endif +} + +static void tabview_init(void) +{ +#if LV_USE_TABVIEW != 0 +#endif +} + +static void tileview_init(void) +{ +#if LV_USE_TILEVIEW != 0 +#endif +} + +static void table_init(void) +{ +#if LV_USE_TABLE != 0 + style_init_reset(&styles->table_cell); + lv_style_set_border_color(&styles->table_cell, LV_STATE_DEFAULT, COLOR_BG_BORDER); + lv_style_set_border_width(&styles->table_cell, LV_STATE_DEFAULT, 1); + lv_style_set_border_side(&styles->table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_TOP | LV_BORDER_SIDE_BOTTOM); + lv_style_set_pad_left(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_right(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_top(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_bottom(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); + +#endif +} + +static void win_init(void) +{ +#if LV_USE_WIN != 0 +#endif +} + +static void tabview_win_shared_init(void) +{ +#if LV_USE_TABVIEW || LV_USE_WIN + style_init_reset(&styles->tabview_btns_bg); + lv_style_set_bg_opa(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->tabview_btns_bg, LV_STATE_DEFAULT, COLOR_BG); + lv_style_set_text_color(&styles->tabview_btns_bg, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_image_recolor(&styles->tabview_btns_bg, LV_STATE_DEFAULT, lv_color_hex(0x979a9f)); + lv_style_set_pad_top(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_left(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_right(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_DPX(7)); + + style_init_reset(&styles->tabview_btns); + lv_style_set_bg_opa(&styles->tabview_btns, LV_STATE_PRESSED, LV_OPA_50); + lv_style_set_bg_color(&styles->tabview_btns, LV_STATE_PRESSED, lv_color_hex3(0x888)); + lv_style_set_text_color(&styles->tabview_btns, LV_STATE_CHECKED, COLOR_SCR_TEXT); + lv_style_set_pad_top(&styles->tabview_btns, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_bottom(&styles->tabview_btns, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_text_color(&styles->tabview_btns, LV_STATE_FOCUSED, theme.color_primary); + lv_style_set_text_color(&styles->tabview_btns, LV_STATE_EDITED, theme.color_secondary); + + style_init_reset(&styles->tabview_indic); + lv_style_set_bg_opa(&styles->tabview_indic, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&styles->tabview_indic, LV_STATE_DEFAULT, theme.color_primary); + lv_style_set_bg_color(&styles->tabview_indic, LV_STATE_EDITED, theme.color_secondary); + lv_style_set_size(&styles->tabview_indic, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_radius(&styles->tabview_indic, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + + style_init_reset(&styles->tabview_page_scrl); + lv_style_set_pad_top(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_bottom(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_left(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_right(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_inner(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); +#endif +} + + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the default + * @param color_primary the primary color of the theme + * @param color_secondary the secondary color for the theme + * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` + * @param font_small pointer to a small font + * @param font_normal pointer to a normal font + * @param font_subtitle pointer to a large font + * @param font_title pointer to a extra large font + * @return a pointer to reference this theme later + */ +lv_theme_t * lv_theme_material_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, + const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle, + const lv_font_t * font_title) +{ + + /* This trick is required only to avoid the garbage collection of + * styles' data if LVGL is used in a binding (e.g. Micropython) + * In a general case styles could be simple `static lv_style_t my style` variables*/ + if(!inited) { + LV_GC_ROOT(_lv_theme_material_styles) = lv_mem_alloc(sizeof(theme_styles_t)); + styles = (theme_styles_t *)LV_GC_ROOT(_lv_theme_material_styles); + } + + theme.color_primary = color_primary; + theme.color_secondary = color_secondary; + theme.font_small = font_small; + theme.font_normal = font_normal; + theme.font_subtitle = font_subtitle; + theme.font_title = font_title; + theme.flags = flags; + + basic_init(); + cont_init(); + btn_init(); + label_init(); + bar_init(); + img_init(); + line_init(); + led_init(); + slider_init(); + switch_init(); + linemeter_init(); + gauge_init(); + arc_init(); + spinner_init(); + chart_init(); + calendar_init(); + cpicker_init(); + checkbox_init(); + btnmatrix_init(); + keyboard_init(); + msgbox_init(); + page_init(); + textarea_init(); + spinbox_init(); + list_init(); + ddlist_init(); + roller_init(); + tabview_init(); + tileview_init(); + table_init(); + win_init(); + tabview_win_shared_init(); + + theme.apply_xcb = NULL; + theme.apply_cb = theme_apply; + + inited = true; + + lv_obj_report_style_mod(NULL); + + return &theme; +} + + +static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name) +{ + LV_UNUSED(th); + + lv_style_list_t * list; + + switch(name) { + case LV_THEME_NONE: + break; + + case LV_THEME_SCR: + list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN); + _lv_style_list_add_style(list, &styles->scr); + break; + case LV_THEME_OBJ: + list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN); + _lv_style_list_add_style(list, &styles->bg); + break; +#if LV_USE_CONT + case LV_THEME_CONT: + list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN); + _lv_style_list_add_style(list, &styles->bg); + break; +#endif + +#if LV_USE_BTN + case LV_THEME_BTN: + list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); + _lv_style_list_add_style(list, &styles->btn); + break; +#endif + +#if LV_USE_BTNMATRIX + case LV_THEME_BTNMATRIX: + list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->pad_small); + + list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->bg_click); + break; +#endif + +#if LV_USE_KEYBOARD + case LV_THEME_KEYBOARD: + list = lv_obj_get_style_list(obj, LV_KEYBOARD_PART_BG); + _lv_style_list_add_style(list, &styles->scr); + _lv_style_list_add_style(list, &styles->kb_bg); + + list = lv_obj_get_style_list(obj, LV_KEYBOARD_PART_BTN); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->bg_click); + break; +#endif + +#if LV_USE_BAR + case LV_THEME_BAR: + list = lv_obj_get_style_list(obj, LV_BAR_PART_BG); + _lv_style_list_add_style(list, &styles->bar_bg); + + list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC); + _lv_style_list_add_style(list, &styles->bar_indic); + break; +#endif + +#if LV_USE_SWITCH + case LV_THEME_SWITCH: + list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG); + _lv_style_list_add_style(list, &styles->bar_bg); + + list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC); + _lv_style_list_add_style(list, &styles->bar_indic); + + list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB); + _lv_style_list_add_style(list, &styles->sw_knob); + break; +#endif + +#if LV_USE_CANVAS + case LV_THEME_CANVAS: + break; +#endif + +#if LV_USE_IMG + case LV_THEME_IMAGE: + break; +#endif + +#if LV_USE_IMGBTN + case LV_THEME_IMGBTN: + break; +#endif + +#if LV_USE_LABEL + case LV_THEME_LABEL: + break; +#endif + +#if LV_USE_LINE + case LV_THEME_LINE: + break; +#endif + +#if LV_USE_ARC + case LV_THEME_ARC: + list = lv_obj_get_style_list(obj, LV_ARC_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->arc_bg); + + list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC); + _lv_style_list_add_style(list, &styles->arc_indic); + + list = lv_obj_get_style_list(obj, LV_ARC_PART_KNOB); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->bg_click); + _lv_style_list_add_style(list, &styles->arc_knob); + break; +#endif + +#if LV_USE_SPINNER + case LV_THEME_SPINNER: + list = lv_obj_get_style_list(obj, LV_SPINNER_PART_BG); + _lv_style_list_add_style(list, &styles->arc_bg); + + list = lv_obj_get_style_list(obj, LV_SPINNER_PART_INDIC); + _lv_style_list_add_style(list, &styles->arc_indic); + break; +#endif + +#if LV_USE_SLIDER + case LV_THEME_SLIDER: + list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG); + _lv_style_list_add_style(list, &styles->bar_bg); + _lv_style_list_add_style(list, &styles->slider_bg); + + list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC); + _lv_style_list_add_style(list, &styles->bar_indic); + + list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB); + _lv_style_list_add_style(list, &styles->slider_knob); + break; +#endif + +#if LV_USE_CHECKBOX + case LV_THEME_CHECKBOX: + list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG); + _lv_style_list_add_style(list, &styles->cb_bg); + + list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET); + _lv_style_list_add_style(list, &styles->btn); + _lv_style_list_add_style(list, &styles->cb_bullet); + break; +#endif + +#if LV_USE_MSGBOX + case LV_THEME_MSGBOX: + list = lv_obj_get_style_list(obj, LV_MSGBOX_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->mbox_bg); + break; + + case LV_THEME_MSGBOX_BTNS: + list = lv_obj_get_style_list(obj, LV_MSGBOX_PART_BTN_BG); + _lv_style_list_add_style(list, &styles->pad_small); + + list = lv_obj_get_style_list(obj, LV_MSGBOX_PART_BTN); + _lv_style_list_add_style(list, &styles->btn); + break; + +#endif +#if LV_USE_LED + case LV_THEME_LED: + list = lv_obj_get_style_list(obj, LV_LED_PART_MAIN); + _lv_style_list_add_style(list, &styles->led); + break; +#endif +#if LV_USE_PAGE + case LV_THEME_PAGE: + list = lv_obj_get_style_list(obj, LV_PAGE_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + + list = lv_obj_get_style_list(obj, LV_PAGE_PART_SCROLLABLE); + _lv_style_list_add_style(list, &styles->pad_inner); + + list = lv_obj_get_style_list(obj, LV_PAGE_PART_SCROLLBAR); + _lv_style_list_add_style(list, &styles->sb); + +#if LV_USE_ANIMATION + list = lv_obj_get_style_list(obj, LV_PAGE_PART_EDGE_FLASH); + _lv_style_list_add_style(list, &styles->edge_flash); +#endif + break; +#endif +#if LV_USE_TABVIEW + case LV_THEME_TABVIEW: + list = lv_obj_get_style_list(obj, LV_TABVIEW_PART_BG); + _lv_style_list_add_style(list, &styles->scr); + + list = lv_obj_get_style_list(obj, LV_TABVIEW_PART_TAB_BG); + _lv_style_list_add_style(list, &styles->tabview_btns_bg); + + list = lv_obj_get_style_list(obj, LV_TABVIEW_PART_INDIC); + _lv_style_list_add_style(list, &styles->tabview_indic); + + list = lv_obj_get_style_list(obj, LV_TABVIEW_PART_TAB_BTN); + _lv_style_list_add_style(list, &styles->tabview_btns); + break; + + case LV_THEME_TABVIEW_PAGE: + list = lv_obj_get_style_list(obj, LV_PAGE_PART_SCROLLABLE); + _lv_style_list_add_style(list, &styles->tabview_page_scrl); + + break; +#endif + +#if LV_USE_TILEVIEW + case LV_THEME_TILEVIEW: + list = lv_obj_get_style_list(obj, LV_TILEVIEW_PART_BG); + _lv_style_list_add_style(list, &styles->scr); + + list = lv_obj_get_style_list(obj, LV_TILEVIEW_PART_SCROLLBAR); + _lv_style_list_add_style(list, &styles->sb); + +#if LV_USE_ANIMATION + list = lv_obj_get_style_list(obj, LV_TILEVIEW_PART_EDGE_FLASH); + _lv_style_list_add_style(list, &styles->edge_flash); +#endif + break; +#endif + + +#if LV_USE_ROLLER + case LV_THEME_ROLLER: + list = lv_obj_get_style_list(obj, LV_ROLLER_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->roller_bg); + + list = lv_obj_get_style_list(obj, LV_ROLLER_PART_SELECTED); + _lv_style_list_add_style(list, &styles->roller_sel); + break; +#endif + +#if LV_USE_OBJMASK + case LV_THEME_OBJMASK: + list = lv_obj_get_style_list(obj, LV_OBJMASK_PART_MAIN); + break; +#endif + +#if LV_USE_LIST + case LV_THEME_LIST: + list = lv_obj_get_style_list(obj, LV_LIST_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->list_bg); + + + list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR); + _lv_style_list_add_style(list, &styles->sb); + break; + + case LV_THEME_LIST_BTN: + list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); + _lv_style_list_add_style(list, &styles->list_btn); + break; +#endif + +#if LV_USE_DROPDOWN + case LV_THEME_DROPDOWN: + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->bg_click); + _lv_style_list_add_style(list, &styles->pad_small); + + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->ddlist_page); + + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR); + _lv_style_list_add_style(list, &styles->sb); + + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED); + _lv_style_list_add_style(list, &styles->ddlist_sel); + break; +#endif + +#if LV_USE_CHART + case LV_THEME_CHART: + list = lv_obj_get_style_list(obj, LV_CHART_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->chart_bg); + _lv_style_list_add_style(list, &styles->pad_small); + + list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES_BG); + _lv_style_list_add_style(list, &styles->pad_small); + _lv_style_list_add_style(list, &styles->chart_series_bg); + + list = lv_obj_get_style_list(obj, LV_CHART_PART_CURSOR); + _lv_style_list_add_style(list, &styles->chart_series_bg); + + list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES); + _lv_style_list_add_style(list, &styles->chart_series); + break; +#endif +#if LV_USE_TABLE + case LV_THEME_TABLE: { + list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + + int idx = 1; /* start value should be 1, not zero, since cell styles + start at 1 due to presence of LV_TABLE_PART_BG=0 + in the enum (lv_table.h) */ + /* declaring idx outside loop to work with older compilers */ + for(; idx <= LV_TABLE_CELL_STYLE_CNT; idx ++) { + list = lv_obj_get_style_list(obj, idx); + _lv_style_list_add_style(list, &styles->table_cell); + } + break; + } +#endif + +#if LV_USE_WIN + case LV_THEME_WIN: + list = lv_obj_get_style_list(obj, LV_WIN_PART_BG); + _lv_style_list_add_style(list, &styles->scr); + + list = lv_obj_get_style_list(obj, LV_WIN_PART_SCROLLBAR); + _lv_style_list_add_style(list, &styles->sb); + + list = lv_obj_get_style_list(obj, LV_WIN_PART_CONTENT_SCROLLABLE); + _lv_style_list_add_style(list, &styles->tabview_page_scrl); + + list = lv_obj_get_style_list(obj, LV_WIN_PART_HEADER); + _lv_style_list_add_style(list, &styles->tabview_btns_bg); + break; + + case LV_THEME_WIN_BTN: + list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); + _lv_style_list_add_style(list, &styles->tabview_btns); + break; +#endif + +#if LV_USE_TEXTAREA + case LV_THEME_TEXTAREA: + list = lv_obj_get_style_list(obj, LV_TEXTAREA_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->pad_small); + + list = lv_obj_get_style_list(obj, LV_TEXTAREA_PART_PLACEHOLDER); + _lv_style_list_add_style(list, &styles->ta_placeholder); + + list = lv_obj_get_style_list(obj, LV_TEXTAREA_PART_CURSOR); + _lv_style_list_add_style(list, &styles->ta_cursor); + + list = lv_obj_get_style_list(obj, LV_TEXTAREA_PART_SCROLLBAR); + _lv_style_list_add_style(list, &styles->sb); + break; + +#endif + + +#if LV_USE_SPINBOX + case LV_THEME_SPINBOX: + list = lv_obj_get_style_list(obj, LV_SPINBOX_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->pad_small); + + list = lv_obj_get_style_list(obj, LV_SPINBOX_PART_CURSOR); + _lv_style_list_add_style(list, &styles->spinbox_cursor); + break; + + case LV_THEME_SPINBOX_BTN: + list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->bg_click); + break; +#endif + +#if LV_USE_CALENDAR + case LV_THEME_CALENDAR: + list = lv_obj_get_style_list(obj, LV_CALENDAR_PART_BG); + _lv_style_list_add_style(list, &styles->bg); + + list = lv_obj_get_style_list(obj, LV_CALENDAR_PART_DATE); + _lv_style_list_add_style(list, &styles->calendar_date_nums); + + list = lv_obj_get_style_list(obj, LV_CALENDAR_PART_HEADER); + _lv_style_list_add_style(list, &styles->calendar_header); + + list = lv_obj_get_style_list(obj, LV_CALENDAR_PART_DAY_NAMES); + _lv_style_list_add_style(list, &styles->calendar_daynames); + break; +#endif +#if LV_USE_CPICKER + case LV_THEME_CPICKER: + list = lv_obj_get_style_list(obj, LV_CPICKER_PART_MAIN); + _lv_style_list_add_style(list, &styles->cpicker_bg); + + list = lv_obj_get_style_list(obj, LV_CPICKER_PART_KNOB); + _lv_style_list_add_style(list, &styles->cpicker_indic); + break; +#endif + +#if LV_USE_LINEMETER + case LV_THEME_LINEMETER: + list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->lmeter); + break; +#endif +#if LV_USE_GAUGE + case LV_THEME_GAUGE: + list = lv_obj_get_style_list(obj, LV_GAUGE_PART_MAIN); + _lv_style_list_add_style(list, &styles->bg); + _lv_style_list_add_style(list, &styles->gauge_main); + + list = lv_obj_get_style_list(obj, LV_GAUGE_PART_MAJOR); + _lv_style_list_add_style(list, &styles->gauge_strong); + + list = lv_obj_get_style_list(obj, LV_GAUGE_PART_NEEDLE); + _lv_style_list_add_style(list, &styles->gauge_needle); + break; +#endif + default: + break; + } + + lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void style_init_reset(lv_style_t * style) +{ + if(inited) lv_style_reset(style); + else lv_style_init(style); +} + +#endif diff --git a/src/lv_widgets/lv_calendar.c b/src/lv_widgets/lv_calendar.c new file mode 100644 index 000000000..5352e177d --- /dev/null +++ b/src/lv_widgets/lv_calendar.c @@ -0,0 +1,1090 @@ +/** + * @file lv_calendar.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_calendar.h" +#if LV_USE_CALENDAR != 0 + +#include "../lv_misc/lv_debug.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_misc/lv_utils.h" +#include "../lv_core/lv_indev.h" +#include "../lv_themes/lv_theme.h" +#include + +/********************* + * DEFINES + *********************/ +#define LV_OBJX_NAME "lv_calendar" + +/********************** + * TYPEDEFS + **********************/ +enum { + DAY_DRAW_PREV_MONTH, + DAY_DRAW_ACT_MONTH, + DAY_DRAW_NEXT_MONTH, +}; +typedef uint8_t day_draw_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_design_res_t lv_calendar_design(lv_obj_t * calendar, const lv_area_t * clip_area, lv_design_mode_t mode); +static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param); +static lv_style_list_t * lv_calendar_get_style(lv_obj_t * calendar, uint8_t part); +static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point); +static lv_coord_t get_header_height(lv_obj_t * calendar); +static lv_coord_t get_day_names_height(lv_obj_t * calendar); +static void draw_header(lv_obj_t * calendar, const lv_area_t * mask); +static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask); +static void draw_dates(lv_obj_t * calendar, const lv_area_t * clip_area); +static bool is_highlighted(lv_obj_t * calendar, day_draw_state_t draw_state, int32_t year, int32_t month, int32_t day); +static bool is_pressed(lv_obj_t * calendar, day_draw_state_t draw_state, int32_t year, int32_t month, int32_t day); +static const char * get_day_name(lv_obj_t * calendar, uint8_t day); +static const char * get_month_name(lv_obj_t * calendar, int32_t month); +static uint8_t get_month_length(int32_t year, int32_t month); +static uint8_t is_leap_year(uint32_t year); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_cb_t ancestor_signal; +static lv_design_cb_t ancestor_design; +#if LV_CALENDAR_WEEK_STARTS_MONDAY != 0 +static const char * day_name[7] = {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}; +#else +static const char * day_name[7] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; +#endif +static const char * month_name[12] = {"January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a calendar object + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("calendar create started"); + + /*Create the ancestor of calendar*/ + lv_obj_t * calendar = lv_obj_create(par, copy); + LV_ASSERT_MEM(calendar); + if(calendar == NULL) return NULL; + + /*Allocate the calendar type specific extended data*/ + lv_calendar_ext_t * ext = lv_obj_allocate_ext_attr(calendar, sizeof(lv_calendar_ext_t)); + LV_ASSERT_MEM(ext); + if(ext == NULL) { + lv_obj_del(calendar); + return NULL; + } + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(calendar); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(calendar); + + /*Initialize the allocated 'ext' */ + ext->today.year = 2020; + ext->today.month = 1; + ext->today.day = 1; + + ext->showed_date.year = 2020; + ext->showed_date.month = 1; + ext->showed_date.day = 1; + + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + + ext->highlighted_dates = NULL; + ext->highlighted_dates_num = 0; + ext->day_names = NULL; + ext->month_names = NULL; + + ext->btn_pressing = 0; + + + lv_style_list_init(&ext->style_date_nums); + lv_style_list_init(&ext->style_day_names); + lv_style_list_init(&ext->style_header); + ext->style_date_nums.skip_trans = 1; + ext->style_day_names.skip_trans = 1; + ext->style_header.skip_trans = 1; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_cb(calendar, lv_calendar_signal); + lv_obj_set_design_cb(calendar, lv_calendar_design); + + /*Init the new calendar calendar*/ + if(copy == NULL) { + lv_theme_apply(calendar, LV_THEME_CALENDAR); + + lv_obj_set_size(calendar, 5 * LV_DPI / 2, 5 * LV_DPI / 2); + + } + /*Copy an existing calendar*/ + else { + lv_calendar_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->today.year = copy_ext->today.year; + ext->today.month = copy_ext->today.month; + ext->today.day = copy_ext->today.day; + + ext->showed_date.year = copy_ext->showed_date.year; + ext->showed_date.month = copy_ext->showed_date.month; + ext->showed_date.day = copy_ext->showed_date.day; + + ext->highlighted_dates = copy_ext->highlighted_dates; + ext->highlighted_dates_num = copy_ext->highlighted_dates_num; + ext->day_names = copy_ext->day_names; + + ext->month_names = copy_ext->month_names; + ext->style_header = copy_ext->style_header; + ext->style_day_names = copy_ext->style_day_names; + /*Refresh the style with new signal function*/ + // lv_obj_refresh_style(new_calendar); + } + + LV_LOG_INFO("calendar created"); + + return calendar; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value + * will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + LV_ASSERT_NULL(today); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->today.year = today->year; + ext->today.month = today->month; + ext->today.day = today->day; + + lv_obj_invalidate(calendar); +} + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value + * will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + LV_ASSERT_NULL(showed); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->showed_date.year = showed->year; + ext->showed_date.month = showed->month; + ext->showed_date.day = showed->day; + + lv_obj_invalidate(calendar); +} + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER + * WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t highlighted[], uint16_t date_num) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + LV_ASSERT_NULL(highlighted); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->highlighted_dates = highlighted; + ext->highlighted_dates_num = date_num; + + lv_obj_invalidate(calendar); +} + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", + * ...}` Only the pointer will be saved so this variable can't be local which will be destroyed + * later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + LV_ASSERT_NULL(day_names); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->day_names = day_names; + lv_obj_invalidate(calendar); +} + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param month_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", + * ...}` Only the pointer will be saved so this variable can't be local which will be destroyed + * later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** month_names) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + LV_ASSERT_NULL(month_names); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->month_names = month_names; + lv_obj_invalidate(calendar); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->today; +} + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->showed_date; +} + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + * `NULL` if not date pressed (e.g. the header) + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->pressed_date.year != 0 ? &ext->pressed_date : NULL; +} + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->highlighted_dates; +} + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->highlighted_dates_num; +} + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->day_names; +} + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->month_names; +} + +/** + * Get the day of the week + * @param year a year + * @param month a month (1..12) + * @param day a day (1..31) + * @return [0..6] which means [Sun..Sat] or [Mon..Sun] depending on LV_CALENDAR_WEEK_STARTS_MONDAY + */ +uint8_t lv_calendar_get_day_of_week(uint32_t year, uint32_t month, uint32_t day) +{ + uint32_t a = month < 3 ? 1 : 0; + uint32_t b = year - a; + +#if LV_CALENDAR_WEEK_STARTS_MONDAY + uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + b + (b / 4) - (b / 100) + (b / 400) - 1) % 7; +#else + uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + b + (b / 4) - (b / 100) + (b / 400)) % 7; +#endif + + return day_of_week; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the calendars + * @param calendar pointer to an object + * @param clip_area the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return an element of `lv_design_res_t` + */ +static lv_design_res_t lv_calendar_design(lv_obj_t * calendar, const lv_area_t * clip_area, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(calendar, clip_area, mode); + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + ancestor_design(calendar, clip_area, mode); + + draw_header(calendar, clip_area); + draw_day_names(calendar, clip_area); + draw_dates(calendar, clip_area); + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(calendar, clip_area, mode); + } + + return LV_DESIGN_RES_OK; +} + +/** + * Signal function of the calendar + * @param calendar pointer to a calendar object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param) +{ + lv_res_t res; + if(sign == LV_SIGNAL_GET_STYLE) { + lv_get_style_info_t * info = param; + info->result = lv_calendar_get_style(calendar, info->part); + if(info->result != NULL) return LV_RES_OK; + else return ancestor_signal(calendar, sign, param); + return LV_RES_OK; + } + + /* Include the ancient signal function */ + res = ancestor_signal(calendar, sign, param); + if(res != LV_RES_OK) return res; + if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME); + + if(sign == LV_SIGNAL_CLEANUP) { + lv_obj_clean_style_list(calendar, LV_CALENDAR_PART_HEADER); + lv_obj_clean_style_list(calendar, LV_CALENDAR_PART_DAY_NAMES); + lv_obj_clean_style_list(calendar, LV_CALENDAR_PART_DATE); + } + else if(sign == LV_SIGNAL_PRESSING) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_area_t header_area; + lv_area_copy(&header_area, &calendar->coords); + header_area.y2 = header_area.y1 + get_header_height(calendar); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + + /*If the header is pressed mark an arrow as pressed*/ + if(_lv_area_is_point_on(&header_area, &p, 0)) { + if(p.x < header_area.x1 + lv_area_get_width(&header_area) / 2) { + if(ext->btn_pressing != -1) lv_obj_invalidate(calendar); + ext->btn_pressing = -1; + } + else { + if(ext->btn_pressing != 1) lv_obj_invalidate(calendar); + ext->btn_pressing = 1; + } + + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + } + /*If a day is pressed save it*/ + else if(calculate_touched_day(calendar, &p)) { + ext->btn_pressing = 0; + lv_obj_invalidate(calendar); + } + /*Else set a default state*/ + else { + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->btn_pressing = 0; + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + lv_obj_invalidate(calendar); + + } + else if(sign == LV_SIGNAL_RELEASED) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->btn_pressing < 0) { + if(ext->showed_date.month <= 1) { + ext->showed_date.month = 12; + ext->showed_date.year--; + } + else { + ext->showed_date.month--; + } + } + else if(ext->btn_pressing > 0) { + if(ext->showed_date.month >= 12) { + ext->showed_date.month = 1; + ext->showed_date.year++; + } + else { + ext->showed_date.month++; + } + } + else if(ext->pressed_date.year != 0) { + res = lv_event_send(calendar, LV_EVENT_VALUE_CHANGED, NULL); + if(res != LV_RES_OK) return res; + + } + + ext->btn_pressing = 0; + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + lv_obj_invalidate(calendar); + } + else if(sign == LV_SIGNAL_CONTROL) { +#if LV_USE_GROUP + uint8_t c = *((uint8_t *)param); + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(c == LV_KEY_RIGHT || c == LV_KEY_UP) { + if(ext->showed_date.month >= 12) { + ext->showed_date.month = 1; + ext->showed_date.year++; + } + else { + ext->showed_date.month++; + } + lv_obj_invalidate(calendar); + } + else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) { + if(ext->showed_date.month <= 1) { + ext->showed_date.month = 12; + ext->showed_date.year--; + } + else { + ext->showed_date.month--; + } + lv_obj_invalidate(calendar); + } +#endif + } + + return res; +} + +/** + * Get the style descriptor of a part of the object + * @param page pointer the object + * @param part the part from `lv_calendar_part_t`. (LV_CALENDAR_PART_...) + * @return pointer to the style descriptor of the specified part + */ +static lv_style_list_t * lv_calendar_get_style(lv_obj_t * calendar, uint8_t part) +{ + LV_ASSERT_OBJ(calendar, LV_OBJX_NAME); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_style_list_t * style_dsc_p; + + + switch(part) { + case LV_CALENDAR_PART_BG: + style_dsc_p = &calendar->style_list; + break; + case LV_CALENDAR_PART_HEADER: + style_dsc_p = &ext->style_header; + break; + case LV_CALENDAR_PART_DAY_NAMES: + style_dsc_p = &ext->style_day_names; + break; + case LV_CALENDAR_PART_DATE: + style_dsc_p = &ext->style_date_nums; + break; + default: + style_dsc_p = NULL; + } + + return style_dsc_p; +} + +/** + * It will check if the days part of calendar is touched + * and if it is, it will calculate the day and put it in pressed_date of calendar object. + * @param calendar pointer to a calendar object + * @param pointer to a point + * @return true: days part of calendar is touched and its related date is put in pressed date + * false: the point is out of days part area. + */ +static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point) +{ + lv_area_t days_area; + lv_area_copy(&days_area, &calendar->coords); + lv_style_int_t left = lv_obj_get_style_pad_left(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t right = lv_obj_get_style_pad_right(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t top = lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t bottom = lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_DATE); + + days_area.x1 += left; + days_area.x2 -= right; + days_area.y1 = calendar->coords.y1 + get_header_height(calendar) + get_day_names_height(calendar) + top; + days_area.y2 -= bottom; + + if(_lv_area_is_point_on(&days_area, touched_point, 0)) { + lv_coord_t w = (days_area.x2 - days_area.x1 + 1) / 7; + lv_coord_t h = (days_area.y2 - days_area.y1 + 1) / 6; + uint8_t x_pos = 0; + x_pos = (touched_point->x - days_area.x1) / w; + if(x_pos > 6) x_pos = 6; + uint8_t y_pos = 0; + y_pos = (touched_point->y - days_area.y1) / h; + if(y_pos > 5) y_pos = 5; + + uint8_t i_pos = 0; + i_pos = (y_pos * 7) + x_pos; + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(i_pos < lv_calendar_get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1)) { + ext->pressed_date.year = ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0); + ext->pressed_date.month = ext->showed_date.month == 1 ? 12 : (ext->showed_date.month - 1); + ext->pressed_date.day = get_month_length(ext->pressed_date.year, ext->pressed_date.month) - + lv_calendar_get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + 1 + i_pos; + } + else if(i_pos < (lv_calendar_get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + + get_month_length(ext->showed_date.year, ext->showed_date.month))) { + ext->pressed_date.year = ext->showed_date.year; + ext->pressed_date.month = ext->showed_date.month; + ext->pressed_date.day = i_pos + 1 - lv_calendar_get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1); + } + else if(i_pos < 42) { + ext->pressed_date.year = ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0); + ext->pressed_date.month = ext->showed_date.month == 12 ? 1 : (ext->showed_date.month + 1); + ext->pressed_date.day = i_pos + 1 - lv_calendar_get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) - + get_month_length(ext->showed_date.year, ext->showed_date.month); + } + return true; + } + else { + return false; + } +} + +/** + * Get the height of a calendar's header based on it's style + * @param calendar point to a calendar + * @return the header's height + */ +static lv_coord_t get_header_height(lv_obj_t * calendar) +{ + const lv_font_t * font = lv_obj_get_style_text_font(calendar, LV_CALENDAR_PART_HEADER); + lv_style_int_t top = lv_obj_get_style_margin_top(calendar, LV_CALENDAR_PART_HEADER) + + lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_HEADER); + lv_style_int_t bottom = lv_obj_get_style_margin_bottom(calendar, LV_CALENDAR_PART_HEADER) + + lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_HEADER); + + return lv_font_get_line_height(font) + top + bottom; +} + +/** + * Get the height of a calendar's day_names based on it's style + * @param calendar point to a calendar + * @return the day_names's height + */ +static lv_coord_t get_day_names_height(lv_obj_t * calendar) +{ + const lv_font_t * font = lv_obj_get_style_text_font(calendar, LV_CALENDAR_PART_DAY_NAMES); + lv_style_int_t top = lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_DAY_NAMES); + lv_style_int_t bottom = lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_DAY_NAMES); + + return lv_font_get_line_height(font) + top + bottom; +} + +/** + * Draw the calendar header with month name and arrows + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_header(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_style_int_t header_left = lv_obj_get_style_pad_left(calendar, LV_CALENDAR_PART_HEADER); + lv_style_int_t header_right = lv_obj_get_style_pad_right(calendar, LV_CALENDAR_PART_HEADER); + const lv_font_t * font = lv_obj_get_style_text_font(calendar, LV_CALENDAR_PART_HEADER); + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + lv_area_t header_area; + header_area.x1 = calendar->coords.x1; + header_area.x2 = calendar->coords.x2; + header_area.y1 = calendar->coords.y1 + lv_obj_get_style_margin_top(calendar, LV_CALENDAR_PART_HEADER); + header_area.y2 = header_area.y1 + lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_HEADER) + + lv_font_get_line_height(font) + lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_HEADER); + + lv_draw_rect_dsc_t header_rect_dsc; + lv_draw_rect_dsc_init(&header_rect_dsc); + lv_obj_init_draw_rect_dsc(calendar, LV_CALENDAR_PART_HEADER, &header_rect_dsc); + lv_draw_rect(&header_area, mask, &header_rect_dsc); + + lv_state_t state_ori = calendar->state; + + /*Add the year + month name*/ + char txt_buf[64]; + _lv_utils_num_to_str(ext->showed_date.year, txt_buf); + txt_buf[4] = ' '; + txt_buf[5] = '\0'; + strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month)); + + calendar->state = LV_STATE_DEFAULT; + _lv_obj_disable_style_caching(calendar, true); + + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + lv_obj_init_draw_label_dsc(calendar, LV_CALENDAR_PART_HEADER, &label_dsc); + label_dsc.flag = LV_TXT_FLAG_CENTER; + header_area.y1 += lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_HEADER); + header_area.y2 -= lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_HEADER); + lv_draw_label(&header_area, mask, &label_dsc, txt_buf, NULL); + + calendar->state = state_ori; /*Restore the state*/ + + /*Add the left arrow*/ + if(ext->btn_pressing < 0) calendar->state |= LV_STATE_PRESSED; + else calendar->state &= ~(LV_STATE_PRESSED); + + header_area.x1 += header_left; + + lv_draw_label_dsc_init(&label_dsc); + lv_obj_init_draw_label_dsc(calendar, LV_CALENDAR_PART_HEADER, &label_dsc); + lv_draw_label(&header_area, mask, &label_dsc, LV_SYMBOL_LEFT, NULL); + + calendar->state = state_ori; /*Restore the state*/ + + /*Add the right arrow*/ + if(ext->btn_pressing > 0) calendar->state |= LV_STATE_PRESSED; + else calendar->state &= ~(LV_STATE_PRESSED); + + header_area.x1 = header_area.x2 - header_right - _lv_txt_get_width(LV_SYMBOL_RIGHT, (uint16_t)strlen(LV_SYMBOL_RIGHT), + font, 0, LV_TXT_FLAG_NONE); + + lv_draw_label_dsc_init(&label_dsc); + lv_obj_init_draw_label_dsc(calendar, LV_CALENDAR_PART_HEADER, &label_dsc); + lv_draw_label(&header_area, mask, &label_dsc, LV_SYMBOL_RIGHT, NULL); + + calendar->state = state_ori; /*Restore the state*/ + _lv_obj_disable_style_caching(calendar, false); +} + +/** + * Draw the day's name below the header + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_style_int_t date_top = lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_bottom = lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_left = lv_obj_get_style_pad_left(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_right = lv_obj_get_style_pad_right(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_inner = lv_obj_get_style_pad_inner(calendar, LV_CALENDAR_PART_DATE); + + lv_coord_t days_w = lv_obj_get_width(calendar) - date_left - date_right; + lv_coord_t box_w = (days_w - date_inner * 6) / 7; + lv_coord_t days_y1 = calendar->coords.y1 + date_top + get_header_height(calendar) + get_day_names_height(calendar); + lv_coord_t days_h = calendar->coords.y2 - days_y1 - date_bottom; + lv_coord_t box_h = (days_h - 5 * date_inner) / 6; + lv_coord_t box_size = LV_MATH_MIN(box_w, box_h); + + lv_style_int_t left = lv_obj_get_style_pad_left(calendar, LV_CALENDAR_PART_DAY_NAMES); + lv_style_int_t right = lv_obj_get_style_pad_right(calendar, LV_CALENDAR_PART_DAY_NAMES); + lv_style_int_t top = lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_DAY_NAMES); + const lv_font_t * font = lv_obj_get_style_text_font(calendar, LV_CALENDAR_PART_DAY_NAMES); + + lv_coord_t w = lv_obj_get_width(calendar) - left - right; + + lv_coord_t label_w = w / 6; + + lv_area_t label_area; + label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + top; + label_area.y2 = label_area.y1 + lv_font_get_line_height(font); + + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + lv_obj_init_draw_label_dsc(calendar, LV_CALENDAR_PART_DAY_NAMES, &label_dsc); + label_dsc.flag = LV_TXT_FLAG_CENTER; + + uint32_t i; + for(i = 0; i < 7; i++) { + label_area.x1 = calendar->coords.x1 + ((w - box_size) * i) / 6 + box_size / 2 - label_w / 2 + left; + label_area.x2 = label_area.x1 + label_w - 1; + + lv_draw_label(&label_area, mask, &label_dsc, get_day_name(calendar, i), NULL); + } +} + +/** + * Draw the date numbers in a matrix + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_dates(lv_obj_t * calendar, const lv_area_t * clip_area) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + const lv_font_t * nums_font = lv_obj_get_style_text_font(calendar, LV_CALENDAR_PART_DATE); + + lv_style_int_t date_top = lv_obj_get_style_pad_top(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_bottom = lv_obj_get_style_pad_bottom(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_left = lv_obj_get_style_pad_left(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_right = lv_obj_get_style_pad_right(calendar, LV_CALENDAR_PART_DATE); + lv_style_int_t date_inner = lv_obj_get_style_pad_inner(calendar, LV_CALENDAR_PART_DATE); + + lv_coord_t days_y1 = calendar->coords.y1 + date_top + get_header_height(calendar) + get_day_names_height(calendar); + lv_coord_t days_h = calendar->coords.y2 - days_y1 - date_bottom; + + /*The state changes without re-caching the styles, disable the use of cache*/ + lv_state_t state_ori = calendar->state; + calendar->state = LV_STATE_DEFAULT; + _lv_obj_disable_style_caching(calendar, true); + + lv_state_t month_state = LV_STATE_DISABLED; + + uint8_t day_cnt; + lv_coord_t days_w = lv_obj_get_width(calendar) - date_left - date_right; + lv_coord_t box_w = (days_w - date_inner * 6) / 7; + lv_coord_t box_h = (days_h - 5 * date_inner) / 6; + lv_coord_t box_size = LV_MATH_MIN(box_w, box_h); + + uint8_t month_start_day = lv_calendar_get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1); + + day_draw_state_t draw_state; + + /*If starting with the first day of the week then the previous month is not visible*/ + if(month_start_day == 0) { + day_cnt = 1; + draw_state = DAY_DRAW_ACT_MONTH; + month_state = 0; + } + else { + draw_state = DAY_DRAW_PREV_MONTH; + day_cnt = get_month_length(ext->showed_date.year, ext->showed_date.month - 1); /*Length of the previous month*/ + day_cnt -= month_start_day - 1; /*First visible number of the previous month*/ + month_state = LV_STATE_DISABLED; + } + + bool month_of_today_shown = false; + if(ext->showed_date.year == ext->today.year && ext->showed_date.month == ext->today.month) { + month_of_today_shown = true; + } + + char buf[3]; + + /*Draw 6 weeks*/ + lv_draw_rect_dsc_t rect_dsc; + lv_draw_label_dsc_t label_dsc; + lv_state_t prev_state = 0xFF; + uint32_t week; + for(week = 0; week < 6; week++) { + lv_area_t box_area; + + box_area.y1 = days_y1 + ((days_h - box_size) * week) / 5; + box_area.y2 = box_area.y1 + box_size - 1; + + if(box_area.y1 > clip_area->y2) { + calendar->state = state_ori; + _lv_obj_disable_style_caching(calendar, false); + return; + } + + lv_area_t label_area; + label_area.y1 = box_area.y1 + (lv_area_get_height(&box_area) - lv_font_get_line_height(nums_font)) / 2; + label_area.y2 = label_area.y1 + lv_font_get_line_height(nums_font); + + /*Draw the 7 days of a week*/ + uint32_t day; + for(day = 0; day < 7; day++) { + /*The previous month is over*/ + if(draw_state == DAY_DRAW_PREV_MONTH && day == month_start_day) { + draw_state = DAY_DRAW_ACT_MONTH; + day_cnt = 1; + month_state = 0; + } + /*The current month is over*/ + else if(draw_state == DAY_DRAW_ACT_MONTH && + day_cnt > get_month_length(ext->showed_date.year, ext->showed_date.month)) { + draw_state = DAY_DRAW_NEXT_MONTH; + day_cnt = 1; + month_state = LV_STATE_DISABLED; + } + + if(box_area.y2 < clip_area->y1) { + day_cnt++; + continue; + } + + lv_state_t day_state = month_state; + if(is_pressed(calendar, draw_state, ext->showed_date.year, ext->showed_date.month, day_cnt)) { + day_state |= LV_STATE_PRESSED; + } + if(is_highlighted(calendar, draw_state, ext->showed_date.year, ext->showed_date.month, day_cnt)) { + day_state |= LV_STATE_CHECKED; + } + if(month_of_today_shown && day_cnt == ext->today.day && draw_state == DAY_DRAW_ACT_MONTH) { + day_state |= LV_STATE_FOCUSED; + } + + if(prev_state != day_state) { + lv_draw_rect_dsc_init(&rect_dsc); + lv_draw_label_dsc_init(&label_dsc); + label_dsc.flag = LV_TXT_FLAG_CENTER; + + calendar->state = day_state; + lv_obj_init_draw_label_dsc(calendar, LV_CALENDAR_PART_DATE, &label_dsc); + lv_obj_init_draw_rect_dsc(calendar, LV_CALENDAR_PART_DATE, &rect_dsc); + + prev_state = day_state; + } + + label_area.x1 = calendar->coords.x1 + ((days_w - box_size) * day) / 6 + date_left; + label_area.x2 = label_area.x1 + box_size - 1; + + box_area.x1 = label_area.x1; + box_area.x2 = label_area.x2; + + + lv_draw_rect(&box_area, clip_area, &rect_dsc); + + /*Write the day's number*/ + _lv_utils_num_to_str(day_cnt, buf); + lv_draw_label(&label_area, clip_area, &label_dsc, buf, NULL); + + /*Go to the next day*/ + day_cnt++; + } + } + calendar->state = state_ori; + _lv_obj_disable_style_caching(calendar, false); + + +} + +/** + * Check weather a date is highlighted or not + * @param calendar pointer to a calendar object + * @param draw_state which month is drawn (previous, active, next) + * @param year a year + * @param month a month [1..12] + * @param day a day [1..31] + * @return true: highlighted + */ +static bool is_highlighted(lv_obj_t * calendar, day_draw_state_t draw_state, int32_t year, int32_t month, int32_t day) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + + if(draw_state == DAY_DRAW_PREV_MONTH) { + year -= month == 1 ? 1 : 0; + month = month == 1 ? 12 : month - 1; + } + else if(draw_state == DAY_DRAW_NEXT_MONTH) { + year += month == 12 ? 1 : 0; + month = month == 12 ? 1 : month + 1; + } + + uint32_t i; + for(i = 0; i < ext->highlighted_dates_num; i++) { + if(ext->highlighted_dates[i].year == year && ext->highlighted_dates[i].month == month && + ext->highlighted_dates[i].day == day) { + return true; + } + } + + return false; +} + +/** + * Check weather a date is highlighted or not + * @param calendar pointer to a calendar object + * @param draw_state which month is drawn (previous, active, next) + * @param year a year + * @param month a month [1..12] + * @param day a day [1..31] + * @return true: highlighted + */ +static bool is_pressed(lv_obj_t * calendar, day_draw_state_t draw_state, int32_t year, int32_t month, int32_t day) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + + if(draw_state == DAY_DRAW_PREV_MONTH) { + year -= month == 1 ? 1 : 0; + month = month == 1 ? 12 : month - 1; + } + else if(draw_state == DAY_DRAW_NEXT_MONTH) { + year += month == 12 ? 1 : 0; + month = month == 12 ? 1 : month + 1; + } + + if(year == ext->pressed_date.year && month == ext->pressed_date.month && day == ext->pressed_date.day) return true; + else return false; +} +/** + * Get the day name + * @param calendar pointer to a calendar object + * @param day a day in [0..6] + * @return + */ +static const char * get_day_name(lv_obj_t * calendar, uint8_t day) +{ + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->day_names) + return ext->day_names[day]; + else + return day_name[day]; +} + +/** + * Get the month name + * @param calendar pointer to a calendar object + * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle + * previous year + * @return + */ +static const char * get_month_name(lv_obj_t * calendar, int32_t month) +{ + month--; /*Range of months id [1..12] but range of indexes is [0..11]*/ + if(month < 0) month = 12 + month; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->month_names) + return ext->month_names[month]; + else + return month_name[month]; +} + +/** + * Get the number of days in a month + * @param year a year + * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle + * previous year + * @return [28..31] + */ +static uint8_t get_month_length(int32_t year, int32_t month) +{ + month--; /*Range of months id [1..12] but range of indexes is [0..11]*/ + if(month < 0) { + year--; /*Already in the previous year (won't be less then -12 to skip a whole year)*/ + month = 12 + month; /*`month` is negative, the result will be < 12*/ + } + if(month >= 12) { + year++; + month -= 12; + } + + /*month == 1 is february*/ + return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2; +} + +/** + * Tells whether a year is leap year or not + * @param year a year + * @return 0: not leap year; 1: leap year + */ +static uint8_t is_leap_year(uint32_t year) +{ + return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1; +} + +#endif diff --git a/src/lv_widgets/lv_calendar.h b/src/lv_widgets/lv_calendar.h new file mode 100644 index 000000000..66f2b24ca --- /dev/null +++ b/src/lv_widgets/lv_calendar.h @@ -0,0 +1,208 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_conf_internal.h" + +#if LV_USE_CALENDAR != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Represents a date on the calendar object (platform-agnostic). + */ +typedef struct { + uint16_t year; + int8_t month; + int8_t day; +} lv_calendar_date_t; + +/*Data of calendar*/ +typedef struct { + /*None*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_calendar_date_t today; /*Date of today*/ + lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ + lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an + array defined by the user)*/ + int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/ + uint16_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + lv_calendar_date_t pressed_date; + const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/ + const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/ + + /*Styles*/ + lv_style_list_t style_header; + lv_style_list_t style_day_names; + lv_style_list_t style_date_nums; +} lv_calendar_ext_t; + +/** Calendar parts*/ +enum { + LV_CALENDAR_PART_BG, /**< Background and "normal" date numbers style */ + LV_CALENDAR_PART_HEADER, /** Calendar header style */ + LV_CALENDAR_PART_DAY_NAMES, /** Day name style */ + LV_CALENDAR_PART_DATE, /** Day name style */ +}; +typedef uint8_t lv_calendar_part_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar objects + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value + * will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today); + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value + * will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed); + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER + * WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t highlighted[], uint16_t date_num); + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", + * ...}` Only the pointer will be saved so this variable can't be local which will be destroyed + * later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param month_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", + * ...}` Only the pointer will be saved so this variable can't be local which will be destroyed + * later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** month_names); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar); + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + * `NULL` if not date pressed (e.g. the header) + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar); + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar); + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar); + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar); + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar); + +/** + * Get the day of the week + * @param year a year + * @param month a month (1..12) + * @param day a day (1..31) + * @return [0..6] which means [Sun..Sat] or [Mon..Sun] depending on LV_CALENDAR_WEEK_STARTS_MONDAY + */ +uint8_t lv_calendar_get_day_of_week(uint32_t year, uint32_t month, uint32_t day); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_CALENDAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/src/lv_widgets/lv_chart.c b/src/lv_widgets/lv_chart.c index d0de652dd..2d71b0665 100644 --- a/src/lv_widgets/lv_chart.c +++ b/src/lv_widgets/lv_chart.c @@ -136,6 +136,7 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * obj, lv_color_t color) ser->start_point = 0; ser->ext_buf_assigned = false; + ser->hidden = 0; ser->y_axis = LV_CHART_AXIS_PRIMARY_Y; uint16_t i; @@ -148,6 +149,32 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * obj, lv_color_t color) return ser; } +/** + * Deallocate and remove a data series from a chart + * @param chart pointer to a chart object + * @param series pointer to a data series on 'chart' + */ +void lv_chart_remove_series(lv_obj_t * obj, lv_chart_series_t * series) +{ + LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + LV_ASSERT_NULL(series); + + lv_chart_t * chart = (lv_chart_t *)obj; + if(!series->ext_buf_assigned && series->points) lv_mem_free(series->points); + + _lv_ll_remove(&chart->series_ll, series); + lv_mem_free(series); + + return; +} + +/** + * Add a cursor with a given color + * @param chart pointer to chart object + * @param color color of the cursor + * @param dir direction of the cursor. `LV_CHART_CURSOR_RIGHT/LEFT/TOP/DOWN`. OR-ed values are possible + * @return pointer to the created cursor + */ lv_chart_cursor_t * lv_chart_add_cursor(lv_obj_t * obj, lv_color_t color, lv_cursor_direction_t axes) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); @@ -185,6 +212,22 @@ void lv_chart_clear_series(lv_obj_t * obj, lv_chart_series_t * series) series->start_point = 0; } +/** + * Hide/Unhide a single series of a chart. + * @param chart pointer to a chart object. + * @param series pointer to a series object + * @param hide true: hide the series + */ +void lv_chart_hide_series(lv_obj_t * chart, lv_chart_series_t * series, bool hide) +{ + LV_ASSERT_OBJ(chart, LV_OBJX_NAME); + LV_ASSERT_NULL(series); + + series->hidden = hide ? 1 : 0; + lv_chart_refresh(chart); +} + + /*===================== * Setter functions *====================*/ @@ -228,7 +271,7 @@ void lv_chart_set_y_range(lv_obj_t * obj, lv_chart_axis_t axis, lv_coord_t ymin, if(chart->ymin[axis] == ymin && chart->ymax[axis] == ymax) return; chart->ymin[axis] = ymin; - chart->ymax[axis] = ymax; + chart->ymax[axis] = (ymax == ymin ? ymax + 1 : ymax);; lv_chart_refresh(obj); } @@ -600,6 +643,7 @@ void lv_chart_set_cursor_point(lv_obj_t * obj, lv_chart_cursor_t * cursor, lv_po lv_chart_refresh(obj); } + /*===================== * Getter functions *====================*/ @@ -1074,6 +1118,7 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) /*Go through all data lines*/ _LV_LL_READ_BACK(&chart->series_ll, ser) { + if (ser->hidden) continue; line_dsc.color = ser->color; point_dsc.bg_color = ser->color; area_dsc.bg_color = ser->color; @@ -1213,6 +1258,7 @@ static void draw_series_column(lv_obj_t * obj, const lv_area_t * clip_area) /*Draw the current point of all data line*/ _LV_LL_READ_BACK(&chart->series_ll, ser) { + if (ser->hidden) continue; lv_coord_t start_point = chart->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0; col_a.x1 = x_act; diff --git a/src/lv_widgets/lv_chart.h b/src/lv_widgets/lv_chart.h index e715c1ca1..e747e2a45 100644 --- a/src/lv_widgets/lv_chart.h +++ b/src/lv_widgets/lv_chart.h @@ -71,6 +71,7 @@ typedef struct { lv_color_t color; uint16_t start_point; uint8_t ext_buf_assigned : 1; + uint8_t hidden : 1; lv_chart_axis_t y_axis : 1; } lv_chart_series_t; @@ -152,6 +153,13 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy); */ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color); +/** + * Deallocate and remove a data series from a chart + * @param chart pointer to a chart object + * @param series pointer to a data series on 'chart' + */ +void lv_chart_remove_series(lv_obj_t * chart, lv_chart_series_t * series); + /** * Add a cursor with a given color * @param chart pointer to chart object @@ -168,6 +176,15 @@ lv_chart_cursor_t * lv_chart_add_cursor(lv_obj_t * chart, lv_color_t color, lv_c */ void lv_chart_clear_series(lv_obj_t * chart, lv_chart_series_t * series); +/** + * Hide/Unhide a single series of a chart. + * @param chart pointer to a chart object. + * @param series pointer to a series object + * @param hide true: hide the series + */ +void lv_chart_hide_series(lv_obj_t * chart, lv_chart_series_t * series, bool hide); + + /*===================== * Setter functions *====================*/ diff --git a/src/lv_widgets/lv_cont.h b/src/lv_widgets/lv_cont.h deleted file mode 100644 index 6fc6a2a52..000000000 --- a/src/lv_widgets/lv_cont.h +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @file lv_cont.h - * - */ - -#ifndef LV_CONT_H -#define LV_CONT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include "../lv_conf_internal.h" - -#if LV_USE_CONT != 0 - -#include "../lv_core/lv_obj.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/** Container layout options*/ -enum { - LV_LAYOUT_OFF = 0, /**< No layout */ - LV_LAYOUT_CENTER, /**< Center objects */ - - /** - * COLUMN: - * - Place the object below each other - * - Keep `pad_top` space on the top - * - Keep `pad_inner` space between the objects - */ - LV_LAYOUT_COLUMN_LEFT, /**< Column left align*/ - LV_LAYOUT_COLUMN_MID, /**< Column middle align*/ - LV_LAYOUT_COLUMN_RIGHT, /**< Column right align*/ - - /** - * ROW: - * - Place the object next to each other - * - Keep `pad_left` space on the left - * - Keep `pad_inner` space between the objects - * - If the object which applies the layout has `base_dir == LV_BIDI_DIR_RTL` - * the row will start from the right applying `pad.right` space - */ - LV_LAYOUT_ROW_TOP, /**< Row top align*/ - LV_LAYOUT_ROW_MID, /**< Row middle align*/ - LV_LAYOUT_ROW_BOTTOM, /**< Row bottom align*/ - - - /** - * PRETTY: - * - Place the object next to each other - * - If there is no more space start a new row - * - Respect `pad_left` and `pad_right` when determining the available space in a row - * - Keep `pad_inner` space between the objects in the same row - * - Keep `pad_inner` space between the objects in rows - * - Divide the remaining horizontal space equally - */ - LV_LAYOUT_PRETTY_TOP, /**< Row top align*/ - LV_LAYOUT_PRETTY_MID, /**< Row middle align*/ - LV_LAYOUT_PRETTY_BOTTOM, /**< Row bottom align*/ - - /** - * GRID - * - Place the object next to each other - * - If there is no more space start a new row - * - Respect `pad_left` and `pad_right` when determining the available space in a row - * - Keep `pad_inner` space between the objects in the same row - * - Keep `pad_inner` space between the objects in rows - * - Unlike `PRETTY`, `GRID` always keep `pad_inner` space horizontally between objects - * so it doesn't divide the remaining horizontal space equally - */ - LV_LAYOUT_GRID, /**< Align same-sized object into a grid*/ - - _LV_LAYOUT_LAST -}; -typedef uint8_t lv_layout_t; - -/** - * How to resize the container around the children. - */ -enum { - LV_FIT_NONE, /**< Do not change the size automatically*/ - LV_FIT_TIGHT, /**< Shrink wrap around the children */ - LV_FIT_PARENT, /**< Align the size to the parent's edge*/ - LV_FIT_MAX, /**< Align the size to the parent's edge first but if there is an object out of it - then get larger */ - _LV_FIT_LAST -}; -typedef uint8_t lv_fit_t; - -typedef struct { - /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/ - /*New data for this type */ - lv_layout_t layout : 4; /*A layout from 'lv_layout_t' enum*/ - lv_fit_t fit_left : 2; /*A fit type from `lv_fit_t` enum */ - lv_fit_t fit_right : 2; /*A fit type from `lv_fit_t` enum */ - lv_fit_t fit_top : 2; /*A fit type from `lv_fit_t` enum */ - lv_fit_t fit_bottom : 2; /*A fit type from `lv_fit_t` enum */ -} lv_cont_ext_t; - -/*Part of the container*/ -enum { - LV_CONT_PART_MAIN = LV_OBJ_PART_MAIN, - _LV_CONT_PART_VIRTUAL_LAST = _LV_OBJ_PART_VIRTUAL_LAST, - _LV_CONT_PART_REAL_LAST = _LV_OBJ_PART_REAL_LAST, -}; - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Create a container objects - * @param par pointer to an object, it will be the parent of the new container - * @param copy pointer to a container object, if not NULL then the new object will be copied from it - * @return pointer to the created container - */ -lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy); - -/*===================== - * Setter functions - *====================*/ - -/** - * Set a layout on a container - * @param cont pointer to a container object - * @param layout a layout from 'lv_cont_layout_t' - */ -void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout); - -/** - * Set the fit policy in all 4 directions separately. - * It tell how to change the container's size automatically. - * @param cont pointer to a container object - * @param left left fit policy from `lv_fit_t` - * @param right right fit policy from `lv_fit_t` - * @param top top fit policy from `lv_fit_t` - * @param bottom bottom fit policy from `lv_fit_t` - */ -void lv_cont_set_fit4(lv_obj_t * cont, lv_fit_t left, lv_fit_t right, lv_fit_t top, lv_fit_t bottom); - -/** - * Set the fit policy horizontally and vertically separately. - * It tells how to change the container's size automatically. - * @param cont pointer to a container object - * @param hor horizontal fit policy from `lv_fit_t` - * @param ver vertical fit policy from `lv_fit_t` - */ -static inline void lv_cont_set_fit2(lv_obj_t * cont, lv_fit_t hor, lv_fit_t ver) -{ - lv_cont_set_fit4(cont, hor, hor, ver, ver); -} - -/** - * Set the fit policy in all 4 direction at once. - * It tells how to change the container's size automatically. - * @param cont pointer to a container object - * @param fit fit policy from `lv_fit_t` - */ -static inline void lv_cont_set_fit(lv_obj_t * cont, lv_fit_t fit) -{ - lv_cont_set_fit4(cont, fit, fit, fit, fit); -} - -/*===================== - * Getter functions - *====================*/ - -/** - * Get the layout of a container - * @param cont pointer to container object - * @return the layout from 'lv_cont_layout_t' - */ -lv_layout_t lv_cont_get_layout(const lv_obj_t * cont); - -/** - * Get left fit mode of a container - * @param cont pointer to a container object - * @return an element of `lv_fit_t` - */ -lv_fit_t lv_cont_get_fit_left(const lv_obj_t * cont); - -/** - * Get right fit mode of a container - * @param cont pointer to a container object - * @return an element of `lv_fit_t` - */ -lv_fit_t lv_cont_get_fit_right(const lv_obj_t * cont); - -/** - * Get top fit mode of a container - * @param cont pointer to a container object - * @return an element of `lv_fit_t` - */ -lv_fit_t lv_cont_get_fit_top(const lv_obj_t * cont); - -/** - * Get bottom fit mode of a container - * @param cont pointer to a container object - * @return an element of `lv_fit_t` - */ -lv_fit_t lv_cont_get_fit_bottom(const lv_obj_t * cont); - -/********************** - * MACROS - **********************/ - -#endif /*LV_USE_CONT*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*LV_CONT_H*/ diff --git a/src/lv_widgets/lv_dropdown.c b/src/lv_widgets/lv_dropdown.c index 87a1e7ce3..753eeb935 100644 --- a/src/lv_widgets/lv_dropdown.c +++ b/src/lv_widgets/lv_dropdown.c @@ -241,7 +241,12 @@ void lv_dropdown_add_option(lv_obj_t * obj, const char * option, uint32_t pos) /*Allocate space for the new option*/ size_t old_len = (ext->options == NULL) ? 0 : strlen(ext->options); - size_t ins_len = strlen(option); +#if LV_USE_ARABIC_PERSIAN_CHARS == 0 + size_t ins_len = strlen(option) + 1; +#else + size_t ins_len = _lv_txt_ap_calc_bytes_cnt(option) + 1; +#endif + size_t new_len = ins_len + old_len + 2; /* +2 for terminating NULL and possible \n */ ext->options = lv_mem_realloc(ext->options, new_len + 1); LV_ASSERT_MEM(ext->options); @@ -269,9 +274,13 @@ void lv_dropdown_add_option(lv_obj_t * obj, const char * option, uint32_t pos) char * ins_buf = _lv_mem_buf_get(ins_len + 2); /* + 2 for terminating NULL and possible \n */ LV_ASSERT_MEM(ins_buf); if(ins_buf == NULL) return; +#if LV_USE_ARABIC_PERSIAN_CHARS == 0 strcpy(ins_buf, option); - if(pos < ext->option_cnt) - strcat(ins_buf, "\n"); +#else + _lv_txt_ap_proc(option, ins_buf); +#endif + if(pos < ext->option_cnt) strcat(ins_buf, "\n"); + _lv_txt_ins(ext->options, _lv_txt_encoded_get_char_id(ext->options, insert_pos), ins_buf); _lv_mem_buf_release(ins_buf); @@ -294,10 +303,8 @@ void lv_dropdown_set_selected(lv_obj_t * obj, uint16_t sel_opt) ext->sel_opt_id = sel_opt < ext->option_cnt ? sel_opt : ext->option_cnt - 1; ext->sel_opt_id_orig = ext->sel_opt_id; - /*Move the list to show the current option*/ - if(ext->list != NULL) { - lv_obj_invalidate(ddlist); - } + + lv_obj_invalidate(ddlist); } /** diff --git a/src/lv_widgets/lv_linemeter.c b/src/lv_widgets/lv_linemeter.c index 9255f6cb0..d9f72873f 100644 --- a/src/lv_widgets/lv_linemeter.c +++ b/src/lv_widgets/lv_linemeter.c @@ -447,7 +447,7 @@ void lv_linemeter_draw_scale(lv_obj_t * lmeter, const lv_area_t * clip_area, uin p1.y = y_out_extra; /* Set the color of the lines */ - if((!ext->mirrored && i > level) || (ext->mirrored && i < level)) { + if((!ext->mirrored && i >= level) || (ext->mirrored && i <= level)) { line_dsc.color = end_color; line_dsc.width = end_line_width; } diff --git a/src/lv_widgets/lv_table.c b/src/lv_widgets/lv_table.c index 6d3ec4df5..098f5ff88 100644 --- a/src/lv_widgets/lv_table.c +++ b/src/lv_widgets/lv_table.c @@ -9,13 +9,13 @@ #include "lv_table.h" #if LV_USE_TABLE != 0 -#include "../lv_misc/lv_debug.h" #include "../lv_core/lv_indev.h" +#include "../lv_misc/lv_debug.h" #include "../lv_misc/lv_txt.h" #include "../lv_misc/lv_txt_ap.h" #include "../lv_misc/lv_math.h" -#include "../lv_draw/lv_draw_label.h" #include "../lv_misc/lv_printf.h" +#include "../lv_draw/lv_draw_label.h" #include "../lv_themes/lv_theme.h" /********************* diff --git a/src/lv_widgets/lv_tabview.c b/src/lv_widgets/lv_tabview.c index 2cb2b6bc0..96200ec0a 100644 --- a/src/lv_widgets/lv_tabview.c +++ b/src/lv_widgets/lv_tabview.c @@ -166,7 +166,7 @@ lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy) lv_btnmatrix_set_map(ext->btns, ext->tab_name_ptr); lv_style_list_copy(lv_obj_get_style_list(tabview, LV_TABVIEW_PART_BG_SCROLLABLE), lv_obj_get_style_list(copy, - LV_TABVIEW_PART_BG_SCROLLABLE)); + LV_TABVIEW_PART_BG_SCROLLABLE)); lv_style_list_copy(lv_obj_get_style_list(tabview, LV_TABVIEW_PART_TAB_BG), lv_obj_get_style_list(copy, LV_TABVIEW_PART_TAB_BG)); lv_style_list_copy(lv_obj_get_style_list(tabview, LV_TABVIEW_PART_TAB_BTN), lv_obj_get_style_list(copy, @@ -616,7 +616,7 @@ static lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * p else if(info->part == LV_TABVIEW_PART_TAB_BTN) info->result = lv_obj_get_state(ext->btns, LV_BTNMATRIX_PART_BTN); else if(info->part == LV_TABVIEW_PART_INDIC) info->result = lv_obj_get_state(ext->indic, LV_OBJ_PART_MAIN); else if(info->part == LV_TABVIEW_PART_BG_SCROLLABLE) info->result = lv_obj_get_state(ext->content, - LV_PAGE_PART_SCROLLABLE); + LV_PAGE_PART_SCROLLABLE); return LV_RES_OK; } diff --git a/src/lv_widgets/lv_textarea.c b/src/lv_widgets/lv_textarea.c index 1b1b3b0cd..7551f2429 100644 --- a/src/lv_widgets/lv_textarea.c +++ b/src/lv_widgets/lv_textarea.c @@ -257,8 +257,7 @@ void lv_textarea_add_char(lv_obj_t * ta, uint32_t c) lv_textarea_clear_selection(ta); /*Clear selection*/ if(ext->pwd_mode != 0) { - - ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 2); /*+2: the new char + \0 */ + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + strlen(letter_buf) + 1); /*+2: the new char + \0 */ LV_ASSERT_MEM(ext->pwd_tmp); if(ext->pwd_tmp == NULL) return; @@ -1458,6 +1457,7 @@ static void pwd_char_hider(lv_obj_t * ta) lv_label_set_text(ext->label, txt_tmp); _lv_mem_buf_release(txt_tmp); + refr_cursor_area(ta); } } diff --git a/src/lv_widgets/lv_win.c b/src/lv_widgets/lv_win.c index b0f123ee8..e087e2d19 100644 --- a/src/lv_widgets/lv_win.c +++ b/src/lv_widgets/lv_win.c @@ -92,6 +92,7 @@ lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy) ext->page = NULL; ext->header = NULL; ext->title_txt = lv_mem_alloc(strlen(DEF_TITLE) + 1); + ext->title_txt_align = LV_TXT_FLAG_NONE; strcpy(ext->title_txt, DEF_TITLE); /*Init the new window object*/ @@ -257,11 +258,20 @@ void lv_win_set_title(lv_obj_t * win, const char * title) lv_win_ext_t * ext = lv_obj_get_ext_attr(win); - ext->title_txt = lv_mem_realloc(ext->title_txt, strlen(title) + 1); +#if LV_USE_ARABIC_PERSIAN_CHARS == 0 + size_t len = strlen(title) + 1; +#else + size_t len = _lv_txt_ap_calc_bytes_cnt(title) + 1; +#endif + + ext->title_txt = lv_mem_realloc(ext->title_txt, len + 1); LV_ASSERT_MEM(ext->title_txt); if(ext->title_txt == NULL) return; - +#if LV_USE_ARABIC_PERSIAN_CHARS == 0 strcpy(ext->title_txt, title); +#else + _lv_txt_ap_proc(title, ext->title_txt); +#endif lv_obj_invalidate(ext->header); } @@ -363,6 +373,14 @@ void lv_win_set_drag(lv_obj_t * win, bool en) lv_obj_set_drag(win, en); } +void lv_win_title_set_alignment(lv_obj_t * win, uint8_t alignment) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + ext->title_txt_align = alignment; + +} + /*===================== * Getter functions *====================*/ @@ -491,6 +509,14 @@ lv_coord_t lv_win_get_width(lv_obj_t * win) return lv_obj_get_width_fit(scrl) - left - right; } +uint8_t lv_win_title_get_alignment(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + return ext->title_txt_align; +} + + /*===================== * Other functions *====================*/ @@ -538,11 +564,13 @@ static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * lv_win_ext_t * ext = lv_obj_get_ext_attr(win); lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER); + lv_style_int_t header_right = lv_obj_get_style_pad_right(win, LV_WIN_PART_HEADER); lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); lv_obj_init_draw_label_dsc(header, LV_OBJ_PART_MAIN, &label_dsc); + label_dsc.flag = ext->title_txt_align; lv_area_t txt_area; lv_point_t txt_size; @@ -557,21 +585,41 @@ static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * /*Get x position of the title (should be on the right of the buttons on the left)*/ - lv_coord_t left_btn_offset = 0; + lv_coord_t btn_offset = 0; btn = lv_obj_get_child_back(ext->header, NULL); while(btn != NULL) { if(LV_WIN_BTN_ALIGN_LEFT == lv_win_btn_get_alignment(btn)) { - left_btn_offset += btn_w + header_inner; + btn_offset += btn_w + header_inner; } btn = lv_obj_get_child_back(header, btn); } - - txt_area.x1 = header->coords.x1 + header_left + left_btn_offset; - txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2; - txt_area.x2 = txt_area.x1 + txt_size.x + left_btn_offset; - txt_area.y2 = txt_area.y1 + txt_size.y; - + switch(label_dsc.flag) { + case LV_TXT_FLAG_CENTER: + txt_area.x1 = header->coords.x1 + header_left + btn_offset; + txt_area.x2 = header->coords.x2 - header_right - btn_offset; + txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2; + txt_area.y2 = txt_area.y1 + txt_size.y; + break; + case LV_TXT_FLAG_RIGHT: + txt_area.x1 = header->coords.x1; + txt_area.x2 = header->coords.x2 - header_right - btn_offset; + txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2; + txt_area.y2 = txt_area.y1 + txt_size.y; + break; + case LV_TXT_FLAG_FIT || LV_TXT_FLAG_EXPAND: + txt_area.x1 = header->coords.x1; + txt_area.x2 = header->coords.x2; + txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2; + txt_area.y2 = txt_area.y1 + txt_size.y; + break; + default: + txt_area.x1 = header->coords.x1 + header_left + btn_offset; + txt_area.x2 = txt_area.x1 + txt_size.x + btn_offset; + txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2; + txt_area.y2 = txt_area.y1 + txt_size.y; + break; + } lv_draw_label(&txt_area, clip_area, &label_dsc, ext->title_txt, NULL); } else if(mode == LV_DESIGN_DRAW_POST) { diff --git a/src/lv_widgets/lv_win.h b/src/lv_widgets/lv_win.h index 06e67132d..3bf4bf71b 100644 --- a/src/lv_widgets/lv_win.h +++ b/src/lv_widgets/lv_win.h @@ -57,6 +57,7 @@ typedef struct { lv_obj_t * header; /*Pointer to the header container of the window*/ char * title_txt; /*Pointer to the title label of the window*/ lv_coord_t btn_w; /*Width of the control buttons*/ + uint8_t title_txt_align; /*Control the alignment of the header text*/ } lv_win_ext_t; /** Window parts. */ @@ -175,6 +176,13 @@ void lv_win_set_anim_time(lv_obj_t * win, uint16_t anim_time); */ void lv_win_set_drag(lv_obj_t * win, bool en); +/** + * Set alignment of title text in window header. + * @param win pointer to a window object + * @param alignment set the type of alignment with LV_TXT_FLAGS + */ +void lv_win_title_set_alignment(lv_obj_t * win, uint8_t alignment); + /*===================== * Getter functions *====================*/ @@ -254,6 +262,12 @@ static inline bool lv_win_get_drag(const lv_obj_t * win) return lv_obj_get_drag(win); } +/** + * Get the current alignment of title text in window header. + * @param win pointer to a window object + */ +uint8_t lv_win_title_get_alignment(lv_obj_t * win); + /*===================== * Other functions *====================*/ diff --git a/tests/lv_test_main.c b/tests/lv_test_main.c index beaa4685d..dd7854dcc 100644 --- a/tests/lv_test_main.c +++ b/tests/lv_test_main.c @@ -1,11 +1,11 @@ #include "../lvgl.h" #include #include -#include #include "lv_test_core/lv_test_core.h" #include "lv_test_widgets/lv_test_label.h" #if LV_BUILD_TEST +#include static void hal_init(void); static void dummy_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);