diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dc6dae23d..98f155cd03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v7.9.0 + +### New features +- feat(chart) add lv_chart_remove_series and lv_chart_hide_series +- feat(img_cahce) allow disabling image cacheing + +### Bugfixes + ## v7.8.1 (Plannad at 15.12.2020) ### Bugfixes diff --git a/lv_conf_template.h b/lv_conf_template.h index ec423dfafe..fddd298826 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -240,7 +240,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/lvgl.h b/lvgl.h index 2583fc4225..8aa6b1bc72 100644 --- a/lvgl.h +++ b/lvgl.h @@ -15,8 +15,8 @@ extern "C" { * CURRENT VERSION OF LVGL ***************************/ #define LVGL_VERSION_MAJOR 7 -#define LVGL_VERSION_MINOR 8 -#define LVGL_VERSION_PATCH 1 +#define LVGL_VERSION_MINOR 9 +#define LVGL_VERSION_PATCH 0 #define LVGL_VERSION_INFO "dev" /********************* diff --git a/src/lv_api_map.h b/src/lv_api_map.h index f5f7a5402a..f86a4c6d66 100644 --- a/src/lv_api_map.h +++ b/src/lv_api_map.h @@ -188,7 +188,7 @@ static inline lv_obj_t * lv_page_get_scrl(lv_obj_t * page) #if LV_USE_API_EXTENSION_V7 #if LV_USE_ROLLER -#define LV_ROLLER_MODE_INIFINITE LV_ROLLER_MODE_INFINITE +#define LV_ROLLER_MODE_INIFINITE LV_ROLLER_MODE_INFINITE #endif #if LV_USE_WIN diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 5bf85131d5..1ad9076880 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 @@ -1322,7 +1322,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_obj.c b/src/lv_core/lv_obj.c index c73d58e3f4..d962144d33 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -221,8 +221,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 1e6de095f5..0ad15f0c62 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_img_cache.c b/src/lv_draw/lv_img_cache.c index cef32144f5..2488865c37 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_widgets/lv_chart.c b/src/lv_widgets/lv_chart.c index 481f15b93a..ceff11af21 100644 --- a/src/lv_widgets/lv_chart.c +++ b/src/lv_widgets/lv_chart.c @@ -195,6 +195,7 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, 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; @@ -207,6 +208,33 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, 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 * chart, lv_chart_series_t * series) +{ + LV_ASSERT_OBJ(chart, LV_OBJX_NAME); + LV_ASSERT_NULL(series); + + if(chart == NULL || series == NULL) return; + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(!series->ext_buf_assigned && series->points) lv_mem_free(series->points); + + _lv_ll_remove(&ext->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 * chart, lv_color_t color, lv_cursor_direction_t axes) { LV_ASSERT_OBJ(chart, LV_OBJX_NAME); @@ -246,6 +274,22 @@ void lv_chart_clear_series(lv_obj_t * chart, 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 *====================*/ @@ -666,6 +710,7 @@ void lv_chart_set_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_ lv_chart_refresh(chart); } + /*===================== * Getter functions *====================*/ @@ -1135,6 +1180,7 @@ static void draw_series_line(lv_obj_t * chart, const lv_area_t * series_area, co /*Go through all data lines*/ _LV_LL_READ_BACK(ext->series_ll, ser) { + if (ser->hidden) continue; line_dsc.color = ser->color; point_dsc.bg_color = ser->color; area_dsc.bg_color = ser->color; @@ -1271,6 +1317,7 @@ static void draw_series_column(lv_obj_t * chart, const lv_area_t * series_area, /*Draw the current point of all data line*/ _LV_LL_READ_BACK(ext->series_ll, ser) { + if (ser->hidden) continue; lv_coord_t start_point = ext->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 2bd9fc0695..0234b411d2 100644 --- a/src/lv_widgets/lv_chart.h +++ b/src/lv_widgets/lv_chart.h @@ -74,6 +74,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; @@ -153,6 +154,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 @@ -169,6 +177,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_dropdown.c b/src/lv_widgets/lv_dropdown.c index 253ed19501..446206d694 100644 --- a/src/lv_widgets/lv_dropdown.c +++ b/src/lv_widgets/lv_dropdown.c @@ -356,7 +356,7 @@ void lv_dropdown_set_selected(lv_obj_t * ddlist, 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; - + lv_obj_invalidate(ddlist); } diff --git a/src/lv_widgets/lv_tabview.c b/src/lv_widgets/lv_tabview.c index 2cb2b6bc09..96200ec0ac 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_win.c b/src/lv_widgets/lv_win.c index b0f123ee80..3e4a5f3f8f 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*/ @@ -363,6 +364,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 +500,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 +555,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 +576,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 06e67132d9..3bf4bf71bd 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 *====================*/