From 28e321f223d1c479ffc68e114276de9bbd1f015f Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Sun, 30 Jun 2019 22:05:28 -0400 Subject: [PATCH 01/49] Add lv_img_buf_alloc and lv_img_buf_free functions --- src/lv_draw/lv_draw_img.c | 35 +++++++++++++++++++++++++++++++++++ src/lv_draw/lv_draw_img.h | 16 ++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 2ad32cd5e..125a99067 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -425,6 +425,41 @@ lv_img_src_t lv_img_src_get_type(const void * src) return img_src_type; } +lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + /*Get the pixel size in bytes*/ + uint8_t px_b = lv_img_color_format_get_px_size(cf) / 8; + + lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t)); + if(dsc == NULL) + return NULL; + + memset(dsc, 0, sizeof(lv_img_dsc_t)); + dsc->data_size = px_b * w * h; + dsc->data = lv_mem_alloc(dsc->data_size); + if(dsc->data == NULL) { + lv_mem_free(dsc); + return NULL; + } + memset(dsc->data, 0, dsc->data_size); + + dsc->header.always_zero = 0; + dsc->header.w = w; + dsc->header.h = h; + dsc->header.cf = cf; + return dsc; +} + +void lv_img_buf_free(lv_img_dsc_t *dsc) +{ + if(dsc != NULL) { + if(dsc->data != NULL) + lv_mem_free(dsc->data); + + lv_mem_free(dsc); + } +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 61c604805..fb39a4ee5 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -120,6 +120,22 @@ bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); */ bool lv_img_color_format_has_alpha(lv_img_cf_t cf); +/** + * Allocate an image buffer in RAM + * @param w width of image + * @param h height of image + * @param cf a color format (`LV_IMG_CF_...`) + * @return an allocated image, or NULL on failure + */ +lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Free an allocated image buffer + * @param dsc image buffer to free + */ +void lv_img_buf_free(lv_img_dsc_t *dsc); + + /********************** * MACROS **********************/ From 9ad51e529e7711464a1934530809ab1454ef3da5 Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Mon, 1 Jul 2019 21:38:01 -0400 Subject: [PATCH 02/49] Add API for retrieving raw image bitmap size --- src/lv_draw/lv_draw_img.c | 15 +++++++++---- src/lv_draw/lv_draw_img.h | 47 ++++++++++++++++++++++++++++++++++++--- src/lv_objx/lv_canvas.h | 23 ++++++++++--------- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 125a99067..9d4e7ffa6 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -427,15 +427,21 @@ lv_img_src_t lv_img_src_get_type(const void * src) lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) { - /*Get the pixel size in bytes*/ - uint8_t px_b = lv_img_color_format_get_px_size(cf) / 8; - + /* Allocate image descriptor */ lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t)); if(dsc == NULL) return NULL; memset(dsc, 0, sizeof(lv_img_dsc_t)); - dsc->data_size = px_b * w * h; + + /* Get image data size */ + dsc->data_size = lv_img_buf_get_img_size(w, h, cf); + if(dsc->data_size == 0) { + lv_mem_free(dsc); + return NULL; + } + + /* Allocate raw buffer */ dsc->data = lv_mem_alloc(dsc->data_size); if(dsc->data == NULL) { lv_mem_free(dsc); @@ -443,6 +449,7 @@ lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) } memset(dsc->data, 0, dsc->data_size); + /* Fill in header */ dsc->header.always_zero = 0; dsc->header.w = w; dsc->header.h = h; diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index fb39a4ee5..a3cb56a27 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -20,6 +20,26 @@ extern "C" { * DEFINES *********************/ +/********************** + * MACROS + **********************/ + +#define LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h) +#define LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h) +#define LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h) + +/*+ 1: to be sure no fractional row*/ +#define LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h)) + +/*4 * X: for palette*/ +#define LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2) +#define LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4) +#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16) +#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256) + /********************** * TYPEDEFS **********************/ @@ -135,10 +155,31 @@ lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); */ void lv_img_buf_free(lv_img_dsc_t *dsc); +/** + * Get the memory consumption of a raw bitmap, given color format and dimensions. + * @param w width + * @param h height + * @param cf color format + * @return size in bytes + */ +static inline size_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + switch(cf) { + case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); + case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); + case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); + case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); + case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); + case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); + case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); + case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); + case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); + case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); + default: return 0; + } +} -/********************** - * MACROS - **********************/ #ifdef __cplusplus } /* extern "C" */ diff --git a/src/lv_objx/lv_canvas.h b/src/lv_objx/lv_canvas.h index 1d59d44d6..9f9cf03ed 100644 --- a/src/lv_objx/lv_canvas.h +++ b/src/lv_objx/lv_canvas.h @@ -23,6 +23,7 @@ extern "C" { #include "../lv_core/lv_obj.h" #include "../lv_objx/lv_img.h" +#include "../lv_draw/lv_draw_img.h" /********************* * DEFINES @@ -239,21 +240,21 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_ /********************** * MACROS **********************/ -#define LV_CANVAS_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h) -#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h) -#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h) +#define LV_CANVAS_BUF_SIZE_TRUE_COLOR(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) +#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) +#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) /*+ 1: to be sure no fractional row*/ -#define LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h)) -#define LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h)) -#define LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h)) -#define LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h)) +#define LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) +#define LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) +#define LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) +#define LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) /*4 * X: for palette*/ -#define LV_CANVAS_BUF_SIZE_INDEXED_1BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2) -#define LV_CANVAS_BUF_SIZE_INDEXED_2BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4) -#define LV_CANVAS_BUF_SIZE_INDEXED_4BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16) -#define LV_CANVAS_BUF_SIZE_INDEXED_8BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256) +#define LV_CANVAS_BUF_SIZE_INDEXED_1BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) +#define LV_CANVAS_BUF_SIZE_INDEXED_2BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) +#define LV_CANVAS_BUF_SIZE_INDEXED_4BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) +#define LV_CANVAS_BUF_SIZE_INDEXED_8BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) #endif /*LV_USE_CANVAS*/ From 27155720d5243988be905cba20f8536364b528cc Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Tue, 2 Jul 2019 14:26:52 -0400 Subject: [PATCH 03/49] Switch from size_t to uint32_t --- src/lv_draw/lv_draw_img.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index a3cb56a27..6c9589f7f 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -162,7 +162,7 @@ void lv_img_buf_free(lv_img_dsc_t *dsc); * @param cf color format * @return size in bytes */ -static inline size_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +static inline uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) { switch(cf) { case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); From 55740d2a96aabc934a775d5da207e5d9ae8cfb2e Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Wed, 3 Jul 2019 09:47:08 -0400 Subject: [PATCH 04/49] Move lv_img_buf_get_img_size to C file instead of inlining --- src/lv_draw/lv_draw_img.c | 18 ++++++++++++++++++ src/lv_draw/lv_draw_img.h | 18 +----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 9d4e7ffa6..2475836a5 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -467,6 +467,24 @@ void lv_img_buf_free(lv_img_dsc_t *dsc) } } +uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + switch(cf) { + case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); + case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); + case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); + case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); + case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); + case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); + case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); + case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); + case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); + case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); + default: return 0; + } +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 6c9589f7f..794dd79e6 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -162,23 +162,7 @@ void lv_img_buf_free(lv_img_dsc_t *dsc); * @param cf color format * @return size in bytes */ -static inline uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) -{ - switch(cf) { - case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); - case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); - case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); - case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); - case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); - case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); - case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); - case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); - case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); - case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); - case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); - default: return 0; - } -} +uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); #ifdef __cplusplus From 95149e466f1bda7098812b1892d103eb314bf0aa Mon Sep 17 00:00:00 2001 From: C47D Date: Sun, 7 Jul 2019 12:17:06 -0500 Subject: [PATCH 05/49] [lv_list] Add list layout prototypes --- src/lv_objx/lv_list.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/lv_objx/lv_list.h b/src/lv_objx/lv_list.h index 7b7927841..ba115a808 100644 --- a/src/lv_objx/lv_list.h +++ b/src/lv_objx/lv_list.h @@ -78,6 +78,13 @@ enum { }; typedef uint8_t lv_list_style_t; +/** List layouts. **/ +enum { + LV_LIST_LAYOUT_HOR, + LV_LIST_LAYOUT_VER +} +typedef uint8_t lv_list_layout_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -189,6 +196,13 @@ static inline void lv_list_set_anim_time(lv_obj_t * list, uint16_t anim_time) */ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * style); +/** + * Set layout of a list + * @param list pointer to a list object + * @param layout which layout should be used + */ +void lv_list_set_layout(lv_obj_t * list, lv_list_layout_t layout); + /*===================== * Getter functions *====================*/ @@ -259,6 +273,13 @@ uint16_t lv_list_get_size(const lv_obj_t * list); lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); #endif +/** + * Get layout of a list + * @param list pointer to a list object + * @return layout which layout should be used + */ +lv_list_layout_t lv_list_get_layout(lv_obj_t * list); + /** * Get the scroll bar mode of a list * @param list pointer to a list object From 3654253472d4af0adf2de720eb0a72c93cf6dcea Mon Sep 17 00:00:00 2001 From: C47D Date: Sun, 7 Jul 2019 13:30:19 -0500 Subject: [PATCH 06/49] [lv_list] Fix comments and add implementation of list layout --- src/lv_objx/lv_list.c | 45 +++++++++++++++++++++++++++++++++++++++++-- src/lv_objx/lv_list.h | 9 +++++---- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index 6fedf950d..60fa00096 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -366,6 +366,36 @@ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * } } +/** + * Set layout of a list + * @param list pointer to a list object + * @param layout which layout should be used + */ + void lv_list_set_layout(lv_obj_t * list, lv_list_layout_t layout) + { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + /* Update list layout if necessary */ + if (layout != lv_list_get_layout(list)) { + + /* Get the first button on the list */ + lv_obj_t * btn = lv_list_get_prev_btn(list, NULL); + + /* Visit all buttons on the list and update their layout */ + while(btn != NULL) { + if (LV_LIST_LAYOUT_HOR == layout) { + lv_btn_set_fit2(list, LV_FIT_FLOOD, LV_FIT_TIGHT); + } else { /* LV_LIST_LAYOUT_VER */ + lv_btn_set_fit(list, LV_FIT_TIGHT); + } + + btn = lv_list_get_prev_btn(list, btn); + } + + ext->layout = layout; + } + } + /*===================== * Getter functions *====================*/ @@ -529,15 +559,25 @@ lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list) lv_list_ext_t * ext = lv_obj_get_ext_attr(list); return ext->selected_btn; } - #endif +/** + * Get layout of a list + * @param list pointer to a list object + * @return layout of the list object + */ +lv_list_layout_t lv_list_get_layout(lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->layout; +} + /** * Get a style of a list * @param list pointer to a list object * @param type which style should be get * @return style pointer to a style - * */ + */ const lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type) { const lv_style_t * style = NULL; @@ -558,6 +598,7 @@ const lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type return style; } + /*===================== * Other functions *====================*/ diff --git a/src/lv_objx/lv_list.h b/src/lv_objx/lv_list.h index ba115a808..418058636 100644 --- a/src/lv_objx/lv_list.h +++ b/src/lv_objx/lv_list.h @@ -57,6 +57,7 @@ typedef struct uint16_t size; /*the number of items(buttons) in the list*/ uint8_t single_mode : 1; /* whether single selected mode is enabled */ + uint8_t layout : 1; /* Layout of the list */ #if LV_USE_GROUP lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ @@ -78,10 +79,10 @@ enum { }; typedef uint8_t lv_list_style_t; -/** List layouts. **/ +/** List layouts. */ enum { - LV_LIST_LAYOUT_HOR, - LV_LIST_LAYOUT_VER + LV_LIST_LAYOUT_HOR, /*< List horizontal layout */ + LV_LIST_LAYOUT_VER /*< List vertical layout */ } typedef uint8_t lv_list_layout_t; @@ -276,7 +277,7 @@ lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); /** * Get layout of a list * @param list pointer to a list object - * @return layout which layout should be used + * @return layout of the list object */ lv_list_layout_t lv_list_get_layout(lv_obj_t * list); From 1dfded27d44f2f50a6cfe1a5de23adbc730bc1e8 Mon Sep 17 00:00:00 2001 From: C47D Date: Sun, 7 Jul 2019 18:50:35 -0500 Subject: [PATCH 07/49] [lv_list] Set vertical layout as default --- src/lv_objx/lv_list.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index 60fa00096..554adfeaf 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -90,6 +90,7 @@ lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy) ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; ext->single_mode = false; ext->size = 0; + ext->layout = LV_LIST_LAYOUT_VER; #if LV_USE_GROUP ext->last_sel = NULL; From b4b4c764a3169ae50117ad07eb8e130115fcb62c Mon Sep 17 00:00:00 2001 From: C47D Date: Sun, 7 Jul 2019 23:41:03 -0500 Subject: [PATCH 08/49] [lv_list] Replace lv_list_layout_t with lv_layout_t --- src/lv_objx/lv_list.c | 10 ++++++---- src/lv_objx/lv_list.h | 11 ++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index 554adfeaf..57d6ad66c 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -90,7 +90,7 @@ lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy) ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; ext->single_mode = false; ext->size = 0; - ext->layout = LV_LIST_LAYOUT_VER; + ext->layout = LV_LAYOUT_COL_M; #if LV_USE_GROUP ext->last_sel = NULL; @@ -372,7 +372,7 @@ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * * @param list pointer to a list object * @param layout which layout should be used */ - void lv_list_set_layout(lv_obj_t * list, lv_list_layout_t layout) + void lv_list_set_layout(lv_obj_t * list, lv_layout_t layout) { lv_list_ext_t * ext = lv_obj_get_ext_attr(list); @@ -384,7 +384,7 @@ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * /* Visit all buttons on the list and update their layout */ while(btn != NULL) { - if (LV_LIST_LAYOUT_HOR == layout) { + if (LV_LAYOUT_COL_M == layout) { lv_btn_set_fit2(list, LV_FIT_FLOOD, LV_FIT_TIGHT); } else { /* LV_LIST_LAYOUT_VER */ lv_btn_set_fit(list, LV_FIT_TIGHT); @@ -393,6 +393,8 @@ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * btn = lv_list_get_prev_btn(list, btn); } + lv_page_set_scr_layout(list, layout == LV_LAYOUT_COL_M ? LV_LAYOUT_COL_M : LV_LAYOUT_ROW_M); + ext->layout = layout; } } @@ -567,7 +569,7 @@ lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list) * @param list pointer to a list object * @return layout of the list object */ -lv_list_layout_t lv_list_get_layout(lv_obj_t * list) +lv_layout_t lv_list_get_layout(lv_obj_t * list) { lv_list_ext_t * ext = lv_obj_get_ext_attr(list); return ext->layout; diff --git a/src/lv_objx/lv_list.h b/src/lv_objx/lv_list.h index 418058636..60ce93fe4 100644 --- a/src/lv_objx/lv_list.h +++ b/src/lv_objx/lv_list.h @@ -79,13 +79,6 @@ enum { }; typedef uint8_t lv_list_style_t; -/** List layouts. */ -enum { - LV_LIST_LAYOUT_HOR, /*< List horizontal layout */ - LV_LIST_LAYOUT_VER /*< List vertical layout */ -} -typedef uint8_t lv_list_layout_t; - /********************** * GLOBAL PROTOTYPES **********************/ @@ -202,7 +195,7 @@ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * * @param list pointer to a list object * @param layout which layout should be used */ -void lv_list_set_layout(lv_obj_t * list, lv_list_layout_t layout); +void lv_list_set_layout(lv_obj_t * list, lv_layout_t layout); /*===================== * Getter functions @@ -279,7 +272,7 @@ lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); * @param list pointer to a list object * @return layout of the list object */ -lv_list_layout_t lv_list_get_layout(lv_obj_t * list); +lv_layout_t lv_list_get_layout(lv_obj_t * list); /** * Get the scroll bar mode of a list From a568a131d6c1f29ff4f9c1ec19cff6a0e0269754 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 8 Jul 2019 17:24:30 +0200 Subject: [PATCH 09/49] list: set/get lyout directly, not store in 'ext' --- src/lv_objx/lv_list.c | 36 ++++++++++++++++-------------------- src/lv_objx/lv_list.h | 1 - 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index 57d6ad66c..7e8308cc5 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -90,7 +90,6 @@ lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy) ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; ext->single_mode = false; ext->size = 0; - ext->layout = LV_LAYOUT_COL_M; #if LV_USE_GROUP ext->last_sel = NULL; @@ -374,29 +373,27 @@ void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, const lv_style_t * */ void lv_list_set_layout(lv_obj_t * list, lv_layout_t layout) { - lv_list_ext_t * ext = lv_obj_get_ext_attr(list); - /* Update list layout if necessary */ - if (layout != lv_list_get_layout(list)) { + if (layout == lv_list_get_layout(list)) return; - /* Get the first button on the list */ - lv_obj_t * btn = lv_list_get_prev_btn(list, NULL); - - /* Visit all buttons on the list and update their layout */ - while(btn != NULL) { - if (LV_LAYOUT_COL_M == layout) { - lv_btn_set_fit2(list, LV_FIT_FLOOD, LV_FIT_TIGHT); - } else { /* LV_LIST_LAYOUT_VER */ - lv_btn_set_fit(list, LV_FIT_TIGHT); - } + /* Get the first button on the list */ + lv_obj_t * btn = lv_list_get_prev_btn(list, NULL); - btn = lv_list_get_prev_btn(list, btn); + /* Visit all buttons on the list and update their layout */ + while(btn != NULL) { + /*If a column layout set the buttons' width to list width*/ + if(layout == LV_LAYOUT_COL_M || layout == LV_LAYOUT_COL_L || layout == LV_LAYOUT_COL_R) { + lv_btn_set_fit2(list, LV_FIT_FLOOD, LV_FIT_TIGHT); + } + /*If a row layout set the buttons' width according to the content*/ + else if (layout == LV_LAYOUT_ROW_M || layout == LV_LAYOUT_ROW_T || layout == LV_LAYOUT_ROW_B) { + lv_btn_set_fit(list, LV_FIT_TIGHT); } - lv_page_set_scr_layout(list, layout == LV_LAYOUT_COL_M ? LV_LAYOUT_COL_M : LV_LAYOUT_ROW_M); + btn = lv_list_get_prev_btn(list, btn); + } - ext->layout = layout; - } + lv_page_set_scrl_layout(list, layout); } /*===================== @@ -571,8 +568,7 @@ lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list) */ lv_layout_t lv_list_get_layout(lv_obj_t * list) { - lv_list_ext_t * ext = lv_obj_get_ext_attr(list); - return ext->layout; + return lv_page_get_scrl_layout(list); } /** diff --git a/src/lv_objx/lv_list.h b/src/lv_objx/lv_list.h index 60ce93fe4..9bba6fb89 100644 --- a/src/lv_objx/lv_list.h +++ b/src/lv_objx/lv_list.h @@ -57,7 +57,6 @@ typedef struct uint16_t size; /*the number of items(buttons) in the list*/ uint8_t single_mode : 1; /* whether single selected mode is enabled */ - uint8_t layout : 1; /* Layout of the list */ #if LV_USE_GROUP lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ From ea00b24cdfe4136e412bc528763d7ebdbf2207de Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 15 Jul 2019 15:01:50 +0200 Subject: [PATCH 10/49] add LV_STYLE_CREATE --- src/lv_core/lv_style.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lv_core/lv_style.h b/src/lv_core/lv_style.h index 83c46f123..18f713a5f 100644 --- a/src/lv_core/lv_style.h +++ b/src/lv_core/lv_style.h @@ -272,6 +272,18 @@ extern lv_style_t lv_style_btn_ina; * MACROS **********************/ +/** + * Create and initialize a `static` style + * Example: + * LV_STYLE_CREATE(my_style, &lv_style_plain); + * is equivalent to + * static lv_style_t my_style; + * lv_style_copy(my_style, &lv_style_plain); + * + * If the style to copy is `NULL` `lv_style_plain` will be used. + */ +#define LV_STYLE_CREATE(name, copy_p) static lv_style_t name; lv_style_copy(&name, copy_p == NULL ? &lv_style_plain : copy_p); + #ifdef __cplusplus } /* extern "C" */ #endif From aa2f70fabca0560b33cce34c3e7825b6704b9c6c Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 22 Jul 2019 06:29:58 +0200 Subject: [PATCH 11/49] add lv_printf --- lv_conf_template.h | 8 + src/lv_conf_checker.h | 16 + src/lv_misc/lv_misc.mk | 1 + src/lv_misc/lv_printf.c | 871 ++++++++++++++++++++++++++++++++++++++++ src/lv_misc/lv_printf.h | 75 ++++ 5 files changed, 971 insertions(+) create mode 100644 src/lv_misc/lv_printf.c create mode 100644 src/lv_misc/lv_printf.h diff --git a/lv_conf_template.h b/lv_conf_template.h index 08e9beb9e..978f4cdc6 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -297,6 +297,14 @@ typedef void * lv_font_user_data_t; /*Can break (wrap) texts on these chars*/ #define LV_TXT_BREAK_CHARS " ,.;:-_" +/*Change the built in (v)snprintf functions*/ +#define LV_SPRINTF_CUSTOM 0 +#if LV_SPRINTF_CUSTOM +# define LV_SPRINTF_INCLUDE +# define lv_snprintf snprintf +# define lv_vsnprintf vsnprintf +#endif /*LV_SPRINTF_CUSTOM*/ + /*=================== * LV_OBJ SETTINGS *==================*/ diff --git a/src/lv_conf_checker.h b/src/lv_conf_checker.h index ff7ac05df..b628a3480 100644 --- a/src/lv_conf_checker.h +++ b/src/lv_conf_checker.h @@ -412,6 +412,22 @@ #define LV_TXT_BREAK_CHARS " ,.;:-_" #endif +/*Change the built in (v)snprintf functions*/ +#ifndef LV_SPRINTF_CUSTOM +#define LV_SPRINTF_CUSTOM 0 +#endif +#if LV_SPRINTF_CUSTOM +#ifndef LV_SPRINTF_INCLUDE +# define LV_SPRINTF_INCLUDE +#endif +#ifndef lv_snprintf +# define lv_snprintf snprintf +#endif +#ifndef lv_vsnprintf +# define lv_vsnprintf vsnprintf +#endif +#endif /*LV_SPRINTF_CUSTOM*/ + /*=================== * LV_OBJ SETTINGS *==================*/ diff --git a/src/lv_misc/lv_misc.mk b/src/lv_misc/lv_misc.mk index 41e4720f0..b9615c599 100644 --- a/src/lv_misc/lv_misc.mk +++ b/src/lv_misc/lv_misc.mk @@ -12,6 +12,7 @@ CSRCS += lv_log.c CSRCS += lv_gc.c CSRCS += lv_utils.c CSRCS += lv_async.c +CSRCS += lv_printf.c DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_misc VPATH += :$(LVGL_DIR)/lvgl/src/lv_misc diff --git a/src/lv_misc/lv_printf.c b/src/lv_misc/lv_printf.c new file mode 100644 index 000000000..8c94449c3 --- /dev/null +++ b/src/lv_misc/lv_printf.c @@ -0,0 +1,871 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#include "lv_printf.h" + +#if LV_SPRINTF_CUSTOM == 0 + +#include +#include + + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE +#define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT +#define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#define PRINTF_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) +#include +#endif + + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal _putchar wrapper +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; (void)idx; (void)maxlen; + if (character) { + _putchar(character); + } +} + + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); + } +} + + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) { + } + else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } + else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + + +/////////////////////////////////////////////////////////////////////////////// + +int lv_snprintf(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + +int lv_vsnprintf(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + +#endif /*LV_SPRINTF_CUSTOM*/ + diff --git a/src/lv_misc/lv_printf.h b/src/lv_misc/lv_printf.h new file mode 100644 index 000000000..b3b8598dd --- /dev/null +++ b/src/lv_misc/lv_printf.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _LV_PRINTF_H_ +#define _LV_PRINTF_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../../lv_conf.h" +#endif + +#if LV_SPRINTF_CUSTOM == 0 + +#include +#include + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +int lv_snprintf(char* buffer, size_t count, const char* format, ...); +int lv_vsnprintf(char* buffer, size_t count, const char* format, va_list va); + +#else +#include LV_SPRINTF_INCLUDE +#endif + + +#ifdef __cplusplus +} +#endif + + +#endif // _PRINTF_H_ From 29b145ffb29795d8d5f4e0835fec0792bcb1228c Mon Sep 17 00:00:00 2001 From: Brian Pugh Date: Tue, 23 Jul 2019 09:08:25 -0700 Subject: [PATCH 12/49] lv_txt.c long word text wrapping initial commit (refactor). --- lv_conf_template.h | 9 ++ src/lv_misc/lv_txt.c | 210 +++++++++++++++++++++++++++++++------------ 2 files changed, 162 insertions(+), 57 deletions(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index 978f4cdc6..e3c340025 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -297,6 +297,15 @@ typedef void * lv_font_user_data_t; /*Can break (wrap) texts on these chars*/ #define LV_TXT_BREAK_CHARS " ,.;:-_" +/* If a character is at least this long, will break wherever "prettiest" */ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 + +/* Minimum number of characters of a word to put on a line before a break */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + +/* Minimum number of characters of a word to put on a line after a break */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + /*Change the built in (v)snprintf functions*/ #define LV_SPRINTF_CUSTOM 0 #if LV_SPRINTF_CUSTOM diff --git a/src/lv_misc/lv_txt.c b/src/lv_misc/lv_txt.c index 8b35c7149..febba1c68 100644 --- a/src/lv_misc/lv_txt.c +++ b/src/lv_misc/lv_txt.c @@ -130,6 +130,137 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * size_res->y -= line_space; } +/** + * Get the next word of text. A word is delimited by break characters. + * + * If the word cannot fit in the max_width space, obey LV_TXT_LINE_BREAK_LONG_* rules. + * + * If the next word cannot fit anything, return 0. + * + * If the first character is a break character, returns the next index. + * + * Example calls from lv_txt_get_next_line() assuming sufficent max_width and + * txt = "Test text\n" + * 0123456789 + * + * Calls would be as follows: + * 1. Return i=4, pointing at breakchar ' ', for the string "Test" + * 2. Return i=5, since i=4 was a breakchar. + * 3. Return i=9, pointing at breakchar '\n' + * 4. Parenting lv_txt_get_next_line() would detect subsequent '\0' + * + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @param[out] word_w_ptr width (in pixels) of the parsed word. May be NULL. + * @return the index of the first char of the next word (in byte index not letter index. With UTF-8 they are different) + */ +static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, + lv_txt_flag_t flag, uint32_t *word_w_ptr) +{ + if(txt == NULL || txt[0] == '\0') return 0; + if(font == NULL) return 0; + + if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; + + uint32_t i = 0, i_next = 0, i_next_next = 0; /* Iterating index into txt */ + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t letter = 0; /* Letter at i */ + uint32_t letter_next = 0; /* Letter at i_next */ + lv_coord_t letter_w; + lv_coord_t cur_w = 0; /* Pixel Width of transversed string */ + uint32_t word_len = 0; /* Number of characters in the transversed word */ + uint32_t break_index = NO_BREAK_FOUND; /* only used for "long" words */ + uint32_t break_letter_count = 0; /* Number of characters up to the long word break point */ + + letter = lv_txt_encoded_next(txt, &i_next); + i_next_next = i_next; + + while(txt[i] != '\0') { + letter_next = lv_txt_encoded_next(txt, &i_next_next); + word_len++; + + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + letter_w = lv_font_get_glyph_width(font, letter, letter_next); + cur_w += letter_w; + + + /* Test if this character fits within max_width */ + if( break_index == NO_BREAK_FOUND && cur_w > max_width) { + break_index = i; + if(break_index > 0) { /* zero is possible if first character doesn't fit in width */ + lv_txt_encoded_prev(txt, &break_index); + break_letter_count = word_len - 2; + } + else{ + break_letter_count = word_len - 1; + } + /* break_index is now pointing at the character that doesn't fit */ + } + + /*Check for new line chars and breakchars*/ + if(letter == '\n' || letter == '\r' || is_break_char(letter)) { + /* Update the output width on the first character if it fits. + * Must do this here incase first letter is a break character. */ + if(i == 0 && break_index == NO_BREAK_FOUND && word_w_ptr != NULL) *word_w_ptr = cur_w; + word_len--; + break; + } + + /* Update the output width */ + if( word_w_ptr != NULL && break_index == NO_BREAK_FOUND ) *word_w_ptr = cur_w; + + if(letter_w > 0) { + cur_w += letter_space; + } + + i = i_next; + i_next = i_next_next; + letter = letter_next; + } + + /* Entire Word fits in the provided space */ + if( break_index == NO_BREAK_FOUND ) { + if( word_len == 0 || (letter == '\r' && letter_next == '\n') ) i = i_next; + return i; + } + + /* Word doesn't fit in provided space, but isn't "long" */ + if(word_len < LV_TXT_LINE_BREAK_LONG_LEN) { + if(word_w_ptr != NULL) *word_w_ptr = 0; + return 0; + } + + /* Word is "long," but insufficient amounts can fit in provided space */ + if(break_letter_count < LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN) { + if(word_w_ptr != NULL) *word_w_ptr = 0; + return 0; + } + + /* Word is a "long", but letters may need to be better distributed */ + { + i = break_index; + int32_t n_move = LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN - (word_len - break_letter_count); + /* Move pointer "i" backwards */ + for(;n_move>0; n_move--){ + lv_txt_encoded_prev(txt, &i); + // todo: it would be appropriate to update the returned word width here + // However, in current usage, this doesn't impact anything. + } + } + + return i; +} + /** * Get the next line of text. Check line length and break chars too. * @param txt a '\0' terminated string @@ -139,75 +270,40 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * * @param flags settings for the text from 'txt_flag_type' enum * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) */ -uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t max_width, - lv_txt_flag_t flag) +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag) { if(txt == NULL) return 0; if(font == NULL) return 0; if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; - uint32_t i = 0; - uint32_t i_next = 0; - lv_coord_t cur_w = 0; - uint32_t last_break = NO_BREAK_FOUND; - lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; - uint32_t letter_w; - uint32_t letter = 0; - uint32_t letter_next = 0; + uint32_t i = 0; /* Iterating index into txt */ - letter_next = lv_txt_encoded_next(txt, &i_next); + while(txt[i] != '\0' && max_width > 0) { + uint32_t word_w = 0; + uint32_t advance = lv_txt_get_next_word(&txt[i], font, letter_space, max_width, flag, &word_w); + max_width -= word_w; - while(txt[i] != '\0') { - letter = letter_next; - i = i_next; - letter_next = lv_txt_encoded_next(txt, &i_next); - - /*Handle the recolor command*/ - if((flag & LV_TXT_FLAG_RECOLOR) != 0) { - if(lv_txt_is_cmd(&cmd_state, letter) != false) { - continue; /*Skip the letter is it is part of a command*/ - } + if( advance == 0 ){ + if(i == 0) lv_txt_encoded_next(txt, &i); // prevent inf loops + break; } - /*Check for new line chars*/ - if(letter == '\n' || letter == '\r') { - /*Return with the first letter of the next line*/ - if(letter == '\r' && letter_next == '\n') - return i_next; - else - return i; - } else { /*Check the actual length*/ - letter_w = lv_font_get_glyph_width(font, letter, letter_next); - cur_w += letter_w; + i += advance; - /*If the txt is too long then finish, this is the line end*/ - if(cur_w > max_width) { - /*If a break character was already found break there*/ - if(last_break != NO_BREAK_FOUND) { - i = last_break; - } else { - /* Now this character is out of the area so it will be first character of the next line*/ - /* But 'i' already points to the next character (because of lv_txt_utf8_next) step beck one*/ - lv_txt_encoded_prev(txt, &i); - } + if(txt[i] == '\n') break; + } - /* Do not let to return without doing nothing. - * Find at least one character (Avoid infinite loop )*/ - if(i == 0) lv_txt_encoded_next(txt, &i); - - return i; - } - /*If this char still can fit to this line then check if - * txt can be broken here later */ - else if(is_break_char(letter)) { - last_break = i; /*Save the first char index after break*/ - } - } - - if(letter_w > 0) { - cur_w += letter_space; - } + /* If this is the last of the string, make sure pointer is at NULL-terminator. + * This catches the case, for example of a string ending in "\n" */ + if(txt[i] != '\0'){ + uint32_t i_next = i; + int tmp; + uint32_t letter_next = lv_txt_encoded_next(txt, &i_next); /*Gets current character*/ + tmp = i_next; + letter_next = lv_txt_encoded_next(txt, &i_next); /*Gets subsequent character*/ + if(letter_next == '\0') i = tmp; } return i; From 28505b09e63a6ad18fb97190df7e5bdced9bfee8 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 24 Jul 2019 06:06:41 +0200 Subject: [PATCH 13/49] update lv_conf_checker.h --- src/lv_conf_checker.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/lv_conf_checker.h b/src/lv_conf_checker.h index b628a3480..f78fbfaa0 100644 --- a/src/lv_conf_checker.h +++ b/src/lv_conf_checker.h @@ -412,6 +412,21 @@ #define LV_TXT_BREAK_CHARS " ,.;:-_" #endif +/* If a character is at least this long, will break wherever "prettiest" */ +#ifndef LV_TXT_LINE_BREAK_LONG_LEN +#define LV_TXT_LINE_BREAK_LONG_LEN 12 +#endif + +/* Minimum number of characters of a word to put on a line before a break */ +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 +#endif + +/* Minimum number of characters of a word to put on a line after a break */ +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 +#endif + /*Change the built in (v)snprintf functions*/ #ifndef LV_SPRINTF_CUSTOM #define LV_SPRINTF_CUSTOM 0 From 5a9904fa1255c3b7f3e55f96ac407f4988611056 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 24 Jul 2019 06:07:20 +0200 Subject: [PATCH 14/49] lv_txt_get_next_line: step at least one to avoid infinite loops --- src/lv_misc/lv_txt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lv_misc/lv_txt.c b/src/lv_misc/lv_txt.c index febba1c68..5632c5ad8 100644 --- a/src/lv_misc/lv_txt.c +++ b/src/lv_misc/lv_txt.c @@ -306,6 +306,11 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, if(letter_next == '\0') i = tmp; } + /*Always step at least one to avoid infinite loops*/ + if(i == 0) { + lv_txt_encoded_next(txt, &i); + } + return i; } From 2093b43045cf1d61c4023a4aa3ad9fef93cdcfaa Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Wed, 24 Jul 2019 12:25:48 -0400 Subject: [PATCH 15/49] Add LV_FS_MAX_PATH_LENGTH --- src/lv_misc/lv_fs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lv_misc/lv_fs.h b/src/lv_misc/lv_fs.h index 5b86b8efd..f18242820 100644 --- a/src/lv_misc/lv_fs.h +++ b/src/lv_misc/lv_fs.h @@ -29,6 +29,7 @@ extern "C" { * DEFINES *********************/ #define LV_FS_MAX_FN_LENGTH 64 +#define LV_FS_MAX_PATH_LENGTH 256 /********************** * TYPEDEFS From d845cd73b040339aa0f54ea396c81497cc9a2c07 Mon Sep 17 00:00:00 2001 From: Brian Pugh Date: Sun, 4 Aug 2019 09:33:46 -0700 Subject: [PATCH 16/49] Fix compiler warnings in lv_draw_img.c (#1166) --- src/lv_draw/lv_draw_img.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 2475836a5..19ba77cd3 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -9,6 +9,7 @@ #include "lv_draw_img.h" #include "lv_img_cache.h" #include "../lv_misc/lv_log.h" +#include "../lv_misc/lv_mem.h" /********************* * DEFINES @@ -447,7 +448,7 @@ lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) lv_mem_free(dsc); return NULL; } - memset(dsc->data, 0, dsc->data_size); + memset((uint8_t *)dsc->data, 0, dsc->data_size); /* Fill in header */ dsc->header.always_zero = 0; From ebb29f09fbf47faaf894211f248a503dd632eb59 Mon Sep 17 00:00:00 2001 From: Jan Van Winkel Date: Mon, 5 Aug 2019 14:46:48 +0200 Subject: [PATCH 17/49] Corrected warning in theme material (#1168) Corrected warning for unused variable hue2 in the function style_mod_edit of the material theme in case color depth = 1. --- src/lv_themes/lv_theme_material.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lv_themes/lv_theme_material.c b/src/lv_themes/lv_theme_material.c index 6eb8f0538..6d162bf53 100644 --- a/src/lv_themes/lv_theme_material.c +++ b/src/lv_themes/lv_theme_material.c @@ -830,11 +830,10 @@ static void style_mod(lv_group_t * group, lv_style_t * style) static void style_mod_edit(lv_group_t * group, lv_style_t * style) { - - uint16_t hue2 = (_hue + 300) % 360; - (void)group; /*Unused*/ #if LV_COLOR_DEPTH != 1 + uint16_t hue2 = (_hue + 300) % 360; + /*Make the style to be a little bit orange*/ style->body.border.opa = LV_OPA_COVER; style->body.border.color = LV_COLOR_GREEN; From 22aee91fc2bb5df33a2e90b1dcb59e193c69e521 Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Mon, 5 Aug 2019 13:52:39 -0400 Subject: [PATCH 18/49] Fix two issues with keyboard * Duplicate characters on long press * Certain keys on the numeric keyboard were not auto-repeating --- src/lv_objx/lv_kb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lv_objx/lv_kb.c b/src/lv_objx/lv_kb.c index 03c1260ce..12731855a 100644 --- a/src/lv_objx/lv_kb.c +++ b/src/lv_objx/lv_kb.c @@ -73,8 +73,8 @@ static const char * kb_map_num[] = {"1", "2", "3", LV_SYMBOL_CLOSE, "\n", static const lv_btnm_ctrl_t kb_ctrl_num_map[] = { 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2, 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2, - 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2, - LV_KB_CTRL_BTN_FLAGS | 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 1, LV_KB_CTRL_BTN_FLAGS | 1}; + 1, 1, 1, 2, + 1, 1, 1, 1, 1}; /* clang-format on */ /********************** @@ -323,7 +323,7 @@ const lv_style_t * lv_kb_get_style(const lv_obj_t * kb, lv_kb_style_t type) */ void lv_kb_def_event_cb(lv_obj_t * kb, lv_event_t event) { - if(event != LV_EVENT_VALUE_CHANGED && event != LV_EVENT_LONG_PRESSED_REPEAT) return; + if(event != LV_EVENT_VALUE_CHANGED) return; lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); uint16_t btn_id = lv_btnm_get_active_btn(kb); From 5c735c0fc8e7467239b81644dc7f5fd49ce2c1be Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Mon, 5 Aug 2019 14:22:37 -0400 Subject: [PATCH 19/49] Do not add right padding to calendar label's x1 coordinate --- src/lv_objx/lv_calendar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_objx/lv_calendar.c b/src/lv_objx/lv_calendar.c index ced804db9..36baea3dc 100644 --- a/src/lv_objx/lv_calendar.c +++ b/src/lv_objx/lv_calendar.c @@ -787,7 +787,7 @@ static void draw_days(lv_obj_t * calendar, const lv_area_t * mask) } label_area.x1 = - calendar->coords.x1 + (w * day) / 7 + style_bg->body.padding.left + style_bg->body.padding.right; + calendar->coords.x1 + (w * day) / 7 + style_bg->body.padding.left; label_area.x2 = label_area.x1 + box_w - 1; /*Draw the "today box"*/ From 677e25397ba9a436dbaa9a67440c8ed5d2a6ea8b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 6 Aug 2019 08:47:45 -0400 Subject: [PATCH 20/49] Prevent chart contents from being drawn outside margin (#1169) --- src/lv_objx/lv_chart.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/lv_objx/lv_chart.c b/src/lv_objx/lv_chart.c index 345e8f105..83ae1ab95 100644 --- a/src/lv_objx/lv_chart.c +++ b/src/lv_objx/lv_chart.c @@ -619,11 +619,20 @@ static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_ lv_chart_draw_div(chart, mask); - if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, mask); - if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, mask); - if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, mask); - if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, mask); - if(ext->type & LV_CHART_TYPE_AREA) lv_chart_draw_areas(chart, mask); + /* Adjust the mask to remove the margin (clips chart contents to be within background) */ + + lv_area_t mask_tmp, adjusted_mask; + lv_obj_get_coords(chart, &mask_tmp); + + bool union_ok = lv_area_intersect(&adjusted_mask, mask, &mask_tmp); + + if(union_ok) { + if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, &adjusted_mask); + if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, &adjusted_mask); + if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, &adjusted_mask); + if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, &adjusted_mask); + if(ext->type & LV_CHART_TYPE_AREA) lv_chart_draw_areas(chart, &adjusted_mask); + } lv_chart_draw_axes(chart, mask); } From 9a69d142fe04bd6a4534e3beecd3422f4fc5faaf Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 6 Aug 2019 08:58:15 -0400 Subject: [PATCH 21/49] Update library.json --- library.json | 1 + 1 file changed, 1 insertion(+) diff --git a/library.json b/library.json index 82f9171a0..b2809bb5a 100644 --- a/library.json +++ b/library.json @@ -1,5 +1,6 @@ { "name": "lvgl", + "version": "6.0.1", "keywords": "graphics, gui, embedded, littlevgl", "description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.", "repository": From ba1fba1f10e35de81459c32ca469127298f40a21 Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Tue, 6 Aug 2019 09:28:50 -0400 Subject: [PATCH 22/49] Add lv_label_set_text_fmt --- src/lv_misc/lv_printf.c | 10 --------- src/lv_objx/lv_label.c | 46 +++++++++++++++++++++++++++++++++++++++++ src/lv_objx/lv_label.h | 8 +++++++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/lv_misc/lv_printf.c b/src/lv_misc/lv_printf.c index 8c94449c3..11a39a8ad 100644 --- a/src/lv_misc/lv_printf.c +++ b/src/lv_misc/lv_printf.c @@ -139,16 +139,6 @@ static inline void _out_null(char character, void* buffer, size_t idx, size_t ma } -// internal _putchar wrapper -static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)buffer; (void)idx; (void)maxlen; - if (character) { - _putchar(character); - } -} - - // internal output function wrapper static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) { diff --git a/src/lv_objx/lv_label.c b/src/lv_objx/lv_label.c index 9dfa92260..2f95abdc3 100644 --- a/src/lv_objx/lv_label.c +++ b/src/lv_objx/lv_label.c @@ -13,6 +13,7 @@ #include "../lv_core/lv_group.h" #include "../lv_misc/lv_color.h" #include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_printf.h" /********************* * DEFINES @@ -203,6 +204,51 @@ void lv_label_set_text(lv_obj_t * label, const char * text) lv_label_refr_text(label); } +/** + * Set a new formatted text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param fmt `printf`-like format + */ +void lv_label_set_text_fmt(lv_obj_t * label, const char * fmt, ...) +{ + lv_obj_invalidate(label); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*If text is NULL then refresh */ + if(fmt == NULL) { + lv_label_refr_text(label); + return; + } + + if(ext->text != NULL && ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + + va_list ap, ap2; + va_start(ap, fmt); + va_copy(ap2, ap); + + /*Allocate space for the new text by using trick from C99 standard section 7.19.6.12 */ + uint32_t len = lv_vsnprintf(NULL, 0, fmt, ap); + + va_end(ap); + + + ext->text = lv_mem_alloc(len+1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + ext->text[len-1] = 0; /* Ensure NULL termination */ + + lv_vsnprintf(ext->text, len, fmt, ap2); + + va_end(ap2); + ext->static_txt = 0; /*Now the text is dynamically allocated*/ + + lv_label_refr_text(label); +} + /** * Set a new text for a label from a character array. The array don't has to be '\0' terminated. * Memory will be allocated to store the array by the label. diff --git a/src/lv_objx/lv_label.h b/src/lv_objx/lv_label.h index 16b1a6e8f..2804ef700 100644 --- a/src/lv_objx/lv_label.h +++ b/src/lv_objx/lv_label.h @@ -21,6 +21,7 @@ extern "C" { #if LV_USE_LABEL != 0 +#include #include "../lv_core/lv_obj.h" #include "../lv_font/lv_font.h" #include "../lv_font/lv_symbol_def.h" @@ -124,6 +125,13 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy); */ void lv_label_set_text(lv_obj_t * label, const char * text); +/** + * Set a new formatted text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param fmt `printf`-like format + */ +void lv_label_set_text_fmt(lv_obj_t * label, const char * fmt, ...); + /** * Set a new text for a label from a character array. The array don't has to be '\0' terminated. * Memory will be allocated to store the array by the label. From d4a22cb71361e0f2088f9aaed9680bed34eddcca Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 6 Aug 2019 09:33:05 -0400 Subject: [PATCH 23/49] PlatformIO needs 6.0.2 in library.json --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index b2809bb5a..f634590a6 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "lvgl", - "version": "6.0.1", + "version": "6.0.2", "keywords": "graphics, gui, embedded, littlevgl", "description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.", "repository": From 18eb517cfff51a9a0323030278aaf9aae4cb843c Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 7 Aug 2019 09:39:35 +0200 Subject: [PATCH 24/49] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 8f71b522d..26d296633 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,17 @@

+

+ +

Shape the future of LittlevGL

+ +

+It takes only 5 minutes to tell some information about how you use LittlevGL, what you like about it, what should be improved and the future directions you find reasonable.
+ +![](https://littlevgl.com/external/survey.png) +
+

From 5e8a3e180ee03efc6f22a433a8fd524873bc7d8f Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 7 Aug 2019 09:41:01 +0200 Subject: [PATCH 25/49] Update README.md --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 26d296633..8cb597523 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,16 @@

Shape the future of LittlevGL

-It takes only 5 minutes to tell some information about how you use LittlevGL, what you like about it, what should be improved and the future directions you find reasonable. -
- ![](https://littlevgl.com/external/survey.png) -
+

+

+It takes only 5 minutes to tell some information about how you use LittlevGL, what you like about it, what should be improved and the future directions you find reasonable. +

+ +--- + +

From 7c90b84560aa8cea64c1f8f08b4398d3fb29e7da Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 7 Aug 2019 09:42:02 +0200 Subject: [PATCH 26/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8cb597523..3cf978f44 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

Shape the future of LittlevGL

-![](https://littlevgl.com/external/survey.png) +

From c35c84c7d0675189e93a557fe6a5959243bd6b1b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 15 Aug 2019 09:24:22 -0400 Subject: [PATCH 27/49] Guard uses of antialiasing option with LV_ANTIALIAS --- src/lv_objx/lv_canvas.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lv_objx/lv_canvas.c b/src/lv_objx/lv_canvas.c index 43610f3c3..da08521a8 100644 --- a/src/lv_objx/lv_canvas.c +++ b/src/lv_objx/lv_canvas.c @@ -482,6 +482,7 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord disp.driver.hor_res = dsc->header.w; disp.driver.ver_res = dsc->header.h; +#if LV_ANTIALIAS /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ lv_color_t ctransp = LV_COLOR_TRANSP; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && @@ -490,6 +491,7 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord { disp.driver.antialiasing = 0; } +#endif lv_disp_t * refr_ori = lv_refr_get_disp_refreshing(); lv_refr_set_disp_refreshing(&disp); @@ -642,6 +644,7 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t * points, uint32_t disp.driver.hor_res = dsc->header.w; disp.driver.ver_res = dsc->header.h; +#if LV_ANTIALIAS /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ lv_color_t ctransp = LV_COLOR_TRANSP; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && @@ -650,6 +653,7 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t * points, uint32_t { disp.driver.antialiasing = 0; } +#endif lv_disp_t * refr_ori = lv_refr_get_disp_refreshing(); lv_refr_set_disp_refreshing(&disp); @@ -694,6 +698,7 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t * points, uint32 disp.driver.hor_res = dsc->header.w; disp.driver.ver_res = dsc->header.h; +#if LV_ANTIALIAS /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ lv_color_t ctransp = LV_COLOR_TRANSP; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && @@ -702,6 +707,7 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t * points, uint32 { disp.driver.antialiasing = 0; } +#endif lv_disp_t * refr_ori = lv_refr_get_disp_refreshing(); lv_refr_set_disp_refreshing(&disp); @@ -747,6 +753,7 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_ disp.driver.hor_res = dsc->header.w; disp.driver.ver_res = dsc->header.h; +#if LV_ANTIALIAS /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ lv_color_t ctransp = LV_COLOR_TRANSP; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && @@ -755,6 +762,7 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_ { disp.driver.antialiasing = 0; } +#endif lv_disp_t * refr_ori = lv_refr_get_disp_refreshing(); lv_refr_set_disp_refreshing(&disp); From 71e950614fc534ff99cbbca1b36b69facde48caa Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 16 Aug 2019 13:43:28 +0200 Subject: [PATCH 28/49] roller, ddlist and lv_label_get_letter_on fixes --- src/lv_objx/lv_ddlist.c | 15 ++++++++++----- src/lv_objx/lv_label.c | 15 ++++++++------- src/lv_objx/lv_roller.c | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/lv_objx/lv_ddlist.c b/src/lv_objx/lv_ddlist.c index f49ec0cef..d4c132d2d 100644 --- a/src/lv_objx/lv_ddlist.c +++ b/src/lv_objx/lv_ddlist.c @@ -142,8 +142,10 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy) ext->draw_arrow = copy_ext->draw_arrow; ext->stay_open = copy_ext->stay_open; - /*Refresh the style with new signal function*/ - lv_obj_refresh_style(new_ddlist); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(copy, LV_DDLIST_STYLE_BG)); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, lv_ddlist_get_style(copy, LV_DDLIST_STYLE_SB)); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, lv_ddlist_get_style(copy, LV_DDLIST_STYLE_SEL)); + } LV_LOG_INFO("drop down list created"); @@ -773,13 +775,16 @@ static lv_res_t release_handler(lv_obj_t * ddlist) uint16_t new_opt = 0; const char * txt = lv_label_get_text(ext->label); uint32_t i = 0; - uint32_t line_cnt = 0; + uint32_t i_prev = 0; + + uint32_t letter_cnt = 0; uint32_t letter; - for(line_cnt = 0; line_cnt < letter_i; line_cnt++) { + for(letter_cnt = 0; letter_cnt < letter_i; letter_cnt++) { letter = lv_txt_encoded_next(txt, &i); /*Count he lines to reach the clicked letter. But ignore the last '\n' because it * still belongs to the clicked line*/ - if(letter == '\n' && i != letter_i) new_opt++; + if(letter == '\n' && i_prev != letter_i) new_opt++; + i_prev = i; } ext->sel_opt_id = new_opt; diff --git a/src/lv_objx/lv_label.c b/src/lv_objx/lv_label.c index 9dfa92260..0b6046c76 100644 --- a/src/lv_objx/lv_label.c +++ b/src/lv_objx/lv_label.c @@ -585,14 +585,13 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; uint32_t i = line_start; - uint32_t i_current = i; + uint32_t i_act = i; uint32_t letter; uint32_t letter_next; if(new_line_start > 0) { - while(i <= new_line_start - 1) { - /* Get the current letter. - * Be careful 'i' already points to the next character*/ + while(i < new_line_start) { + /* Get the current letter.*/ letter = lv_txt_encoded_next(txt, &i); /*Get the next letter too for kerning*/ @@ -606,12 +605,14 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) } x += lv_font_get_glyph_width(font, letter, letter_next); - if(pos->x < x) { - i = i_current; + + /*Finish if the x position or the last char of the line is reached*/ + if(pos->x < x || i == new_line_start) { + i = i_act; break; } x += style->text.letter_space; - i_current = i; + i_act = i; } } diff --git a/src/lv_objx/lv_roller.c b/src/lv_objx/lv_roller.c index 05c3b0919..327690776 100644 --- a/src/lv_objx/lv_roller.c +++ b/src/lv_objx/lv_roller.c @@ -498,7 +498,7 @@ static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, lv_coord_t font_h = lv_font_get_line_height(font); if(sign == LV_SIGNAL_DRAG_END) { - /*If dragged then align the list to there be an element in the middle*/ + /*If dragged then align the list to have an element in the middle*/ lv_coord_t label_y1 = ext->ddlist.label->coords.y1 - roller->coords.y1; lv_coord_t label_unit = font_h + style_label->text.line_space; lv_coord_t mid = (roller->coords.y2 - roller->coords.y1) / 2; From bbb0d2f60efc7154597928bfeef94b377ce870d3 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 16 Aug 2019 16:43:05 +0200 Subject: [PATCH 29/49] lv_roller: fix misalignment when an other obj is cliked while rolling --- src/lv_core/lv_indev.c | 15 +++++++++++---- src/lv_objx/lv_ddlist.c | 7 +++++++ src/lv_objx/lv_roller.c | 14 +++++++++++--- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 86e343a60..2d672ac44 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -687,12 +687,14 @@ static void indev_proc_press(lv_indev_proc_t * proc) if(proc->wait_until_release != 0) return; lv_disp_t * disp = indev_act->driver.disp; + bool new_obj_searched = false; /*If there is no last object then search*/ if(indev_obj_act == NULL) { indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_sys(disp)); if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_top(disp)); if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_scr_act(disp)); + new_obj_searched = true; } /*If there is last object but it is not dragged and not protected also search*/ else if(proc->types.pointer.drag_in_prog == 0 && @@ -700,14 +702,21 @@ static void indev_proc_press(lv_indev_proc_t * proc) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_sys(disp)); if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_top(disp)); if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_scr_act(disp)); + new_obj_searched = true; } /*If a dragable or a protected object was the last then keep it*/ else { } + /*The last object might have drag throw. Stop it manually*/ + if(new_obj_searched && proc->types.pointer.last_obj) { + proc->types.pointer.drag_throw_vect.x = 0; + proc->types.pointer.drag_throw_vect.y = 0; + indev_drag_throw(proc); + } + /*If a new object was found reset some variables and send a pressed signal*/ if(indev_obj_act != proc->types.pointer.act_obj) { - proc->types.pointer.last_point.x = proc->types.pointer.act_point.x; proc->types.pointer.last_point.y = proc->types.pointer.act_point.y; @@ -720,6 +729,7 @@ static void indev_proc_press(lv_indev_proc_t * proc) if(indev_reset_check(proc)) return; lv_event_send(last_obj, LV_EVENT_PRESS_LOST, NULL); if(indev_reset_check(proc)) return; + } proc->types.pointer.act_obj = indev_obj_act; /*Save the pressed object*/ @@ -1108,9 +1118,6 @@ static void indev_drag(lv_indev_proc_t * state) lv_obj_set_y(drag_obj, act_y + state->types.pointer.vect.y); } - - - /*If the object didn't moved then clear the invalidated areas*/ if(drag_obj->coords.x1 == prev_x && drag_obj->coords.y1 == prev_y) { // state->types.pointer.drag_in_prog = 0; diff --git a/src/lv_objx/lv_ddlist.c b/src/lv_objx/lv_ddlist.c index d4c132d2d..3deeed174 100644 --- a/src/lv_objx/lv_ddlist.c +++ b/src/lv_objx/lv_ddlist.c @@ -232,6 +232,7 @@ void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h) */ void lv_ddlist_set_fix_width(lv_obj_t * ddlist, lv_coord_t w) { + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); if(w == 0) { lv_cont_set_fit2(ddlist, LV_FIT_TIGHT, lv_cont_get_fit_bottom(ddlist)); } else { @@ -239,6 +240,12 @@ void lv_ddlist_set_fix_width(lv_obj_t * ddlist, lv_coord_t w) lv_obj_set_width(ddlist, w); } + switch(lv_label_get_align(ext->label)) { + case LV_LABEL_ALIGN_LEFT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break; + case LV_LABEL_ALIGN_CENTER: lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0); break; + case LV_LABEL_ALIGN_RIGHT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break; + } + lv_ddlist_refr_size(ddlist, false); } diff --git a/src/lv_objx/lv_roller.c b/src/lv_objx/lv_roller.c index 327690776..287d139b1 100644 --- a/src/lv_objx/lv_roller.c +++ b/src/lv_objx/lv_roller.c @@ -176,9 +176,17 @@ void lv_roller_set_options(lv_obj_t * roller, const char * options, lv_roller_mo void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align) { lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); - lv_mem_assert(ext); - if(ext->ddlist.label == NULL) return; /*Probably the roller is being deleted if the label is NULL.*/ - lv_label_set_align(ext->ddlist.label, align); + + lv_obj_t * label = ext->ddlist.label; + + if(label == NULL) return; /*Probably the roller is being deleted if the label is NULL.*/ + lv_label_set_align(label, align); + + switch(lv_label_get_align(label)) { + case LV_LABEL_ALIGN_LEFT: lv_obj_align(label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break; + case LV_LABEL_ALIGN_CENTER: lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0); break; + case LV_LABEL_ALIGN_RIGHT: lv_obj_align(label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break; + } } /** From 7ea67301d7df8fb5ff35c090cdf0c2653a7956a3 Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Sun, 18 Aug 2019 16:00:57 -0400 Subject: [PATCH 30/49] Fix off-by-one error in lv_label_set_text_fmt --- src/lv_objx/lv_label.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_objx/lv_label.c b/src/lv_objx/lv_label.c index 727a7e9e4..a6cff45f2 100644 --- a/src/lv_objx/lv_label.c +++ b/src/lv_objx/lv_label.c @@ -241,7 +241,7 @@ void lv_label_set_text_fmt(lv_obj_t * label, const char * fmt, ...) if(ext->text == NULL) return; ext->text[len-1] = 0; /* Ensure NULL termination */ - lv_vsnprintf(ext->text, len, fmt, ap2); + lv_vsnprintf(ext->text, len+1, fmt, ap2); va_end(ap2); ext->static_txt = 0; /*Now the text is dynamically allocated*/ From 941409f3f9ef30b75690abd2347f1468914c732d Mon Sep 17 00:00:00 2001 From: seyyah Date: Mon, 19 Aug 2019 16:24:06 +0300 Subject: [PATCH 31/49] docs/CODING_STYLE.md: add src prefix to path (#1174) --- docs/CODING_STYLE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md index b8bb841db..31071e94f 100644 --- a/docs/CODING_STYLE.md +++ b/docs/CODING_STYLE.md @@ -1,6 +1,6 @@ ## File format -Use [lv_misc/lv_templ.c](https://github.com/littlevgl/lvgl/blob/master/lv_misc/lv_templ.c) and [lv_misc/lv_templ.h](https://github.com/littlevgl/lvgl/blob/master/lv_misc/lv_templ.h) +Use [lv_misc/lv_templ.c](https://github.com/littlevgl/lvgl/blob/master/src/lv_misc/lv_templ.c) and [lv_misc/lv_templ.h](https://github.com/littlevgl/lvgl/blob/master/src/lv_misc/lv_templ.h) ## Naming conventions * Words are separated by '_' From 94c95bc9e461847a734a5bde9818fa837d343425 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 21 Aug 2019 09:53:55 -0400 Subject: [PATCH 32/49] lv_table: fix memory leak when deleted (#1178) --- src/lv_objx/lv_table.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lv_objx/lv_table.c b/src/lv_objx/lv_table.c index f3c6bfab6..ec8ebe5b8 100644 --- a/src/lv_objx/lv_table.c +++ b/src/lv_objx/lv_table.c @@ -752,6 +752,8 @@ static lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param ext->cell_data[cell] = NULL; } } + if(ext->cell_data != NULL) + lv_mem_free(ext->cell_data); } else if(sign == LV_SIGNAL_GET_TYPE) { lv_obj_type_t * buf = param; uint8_t i; From 248c3a51ea605ca7b7b7e92c21ac09d02017c211 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 24 Aug 2019 10:15:09 +0200 Subject: [PATCH 33/49] btnm: fix padding.bottom handling --- src/lv_objx/lv_btnm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_objx/lv_btnm.c b/src/lv_objx/lv_btnm.c index 912986245..f9b83b6cf 100644 --- a/src/lv_objx/lv_btnm.c +++ b/src/lv_objx/lv_btnm.c @@ -201,7 +201,7 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[]) /*Make sure the last row is at the bottom of 'btnm'*/ if(map_p_tmp[btn_cnt][0] == '\0') { /*Last row?*/ - btn_h = max_h - act_y + style_bg->body.padding.bottom - 1; + btn_h = lv_obj_get_height(btnm)- act_y - style_bg->body.padding.bottom - 1; } /*Only deal with the non empty lines*/ From c0180b05b47443c7fdeb7d982dff05561fb30f11 Mon Sep 17 00:00:00 2001 From: Harry Jiang Date: Mon, 26 Aug 2019 13:26:49 +0800 Subject: [PATCH 34/49] Fix the read input device example in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cf978f44..a90532560 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device* indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/ lv_indev_drv_register(&indev_drv); /*Finally register the driver*/ -bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data) +bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) { static lv_coord_t last_x = 0; static lv_coord_t last_y = 0; From 3eb06252e9f1ec2e6e24938b7d6e7fbc6dbd4aaf Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 26 Aug 2019 09:05:30 +0200 Subject: [PATCH 35/49] indev: fix lv_indev_enable --- src/lv_core/lv_indev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 2d672ac44..6ec59bdac 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -182,7 +182,7 @@ void lv_indev_enable(lv_indev_t * indev, bool en) { if(!indev) return; - indev->proc.disabled = en ? 1 : 0; + indev->proc.disabled = en ? 0 : 1; } /** From 74d5ac55532dd2d3bd85ab5ebe087a9300f8a1a5 Mon Sep 17 00:00:00 2001 From: HarryManderTait <41089556+HarryManderTait@users.noreply.github.com> Date: Thu, 29 Aug 2019 00:01:50 +1200 Subject: [PATCH 36/49] lv_preload: add constant-speed loader (#1181) --- src/lv_objx/lv_preload.c | 6 ++++-- src/lv_objx/lv_preload.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lv_objx/lv_preload.c b/src/lv_objx/lv_preload.c index eee893203..eca360813 100644 --- a/src/lv_objx/lv_preload.c +++ b/src/lv_objx/lv_preload.c @@ -220,9 +220,10 @@ void lv_preload_set_type(lv_obj_t * preload, lv_preload_type_t type) lv_anim_create(&b); break; } + case LV_PRELOAD_TYPE_CONSTANT_ARC: case LV_PRELOAD_TYPE_SPINNING_ARC: default: { - ext->anim_type = LV_PRELOAD_TYPE_SPINNING_ARC; + ext->anim_type = type; lv_anim_t a; a.var = preload; if(ext->anim_dir == LV_PRELOAD_DIR_FORWARD) { @@ -234,7 +235,8 @@ void lv_preload_set_type(lv_obj_t * preload, lv_preload_type_t type) a.end = 360; } a.exec_cb = (lv_anim_exec_xcb_t)lv_preload_spinner_anim; - a.path_cb = lv_anim_path_ease_in_out; + a.path_cb = (LV_PRELOAD_TYPE_CONSTANT_ARC == type ? + lv_anim_path_linear : lv_anim_path_ease_in_out); a.ready_cb = NULL; a.act_time = 0; a.time = ext->time; diff --git a/src/lv_objx/lv_preload.h b/src/lv_objx/lv_preload.h index cbc7826a6..22b87f32f 100644 --- a/src/lv_objx/lv_preload.h +++ b/src/lv_objx/lv_preload.h @@ -48,6 +48,7 @@ extern "C" { enum { LV_PRELOAD_TYPE_SPINNING_ARC, LV_PRELOAD_TYPE_FILLSPIN_ARC, + LV_PRELOAD_TYPE_CONSTANT_ARC, }; typedef uint8_t lv_preload_type_t; @@ -67,7 +68,7 @@ typedef struct /*New data for this type */ lv_anim_value_t arc_length; /*Length of the spinning indicator in degree*/ uint16_t time; /*Time of one round*/ - lv_preload_type_t anim_type : 1; /*Type of the arc animation*/ + lv_preload_type_t anim_type : 2; /*Type of the arc animation*/ lv_preload_dir_t anim_dir : 1; /*Animation Direction*/ } lv_preload_ext_t; From 1ff1e31ed884c7e90f17140aac3f1732048b9f56 Mon Sep 17 00:00:00 2001 From: tgillbe Date: Wed, 28 Aug 2019 13:55:22 +0100 Subject: [PATCH 37/49] Add transparency support to indexed images --- lv_conf_template.h | 3 +++ src/lv_conf_checker.h | 5 +++++ src/lv_draw/lv_draw_img.c | 10 ++++----- src/lv_draw/lv_img_decoder.c | 40 +++++++++++++++++++++++++++++++++--- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index e3c340025..8ee14a1c4 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -43,6 +43,9 @@ /*Images pixels with this color will not be drawn (with chroma keying)*/ #define LV_COLOR_TRANSP LV_COLOR_LIME /*LV_COLOR_LIME: pure green*/ +/* Enable chroma keying for indexed images. */ +#define LV_INDEXED_CHROMA 1 + /* Enable anti-aliasing (lines, and radiuses will be smoothed) */ #define LV_ANTIALIAS 1 diff --git a/src/lv_conf_checker.h b/src/lv_conf_checker.h index f78fbfaa0..9bc2b1a3b 100644 --- a/src/lv_conf_checker.h +++ b/src/lv_conf_checker.h @@ -50,6 +50,11 @@ #define LV_COLOR_TRANSP LV_COLOR_LIME /*LV_COLOR_LIME: pure green*/ #endif +/* Enable chroma keying for indexed images. */ +#ifndef LV_INDEXED_CHROMA +#define LV_INDEXED_CHROMA 1 +#endif + /* Enable anti-aliasing (lines, and radiuses will be smoothed) */ #ifndef LV_ANTIALIAS #define LV_ANTIALIAS 1 diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 6a03d9d74..65d54703d 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -401,11 +401,7 @@ bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) switch(cf) { case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: - case LV_IMG_CF_RAW_CHROMA_KEYED: - case LV_IMG_CF_INDEXED_1BIT: - case LV_IMG_CF_INDEXED_2BIT: - case LV_IMG_CF_INDEXED_4BIT: - case LV_IMG_CF_INDEXED_8BIT: is_chroma_keyed = true; break; + case LV_IMG_CF_RAW_CHROMA_KEYED: is_chroma_keyed = true; break; default: is_chroma_keyed = false; break; } @@ -424,6 +420,10 @@ bool lv_img_color_format_has_alpha(lv_img_cf_t cf) switch(cf) { case LV_IMG_CF_TRUE_COLOR_ALPHA: case LV_IMG_CF_RAW_ALPHA: + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_INDEXED_8BIT: case LV_IMG_CF_ALPHA_1BIT: case LV_IMG_CF_ALPHA_2BIT: case LV_IMG_CF_ALPHA_4BIT: diff --git a/src/lv_draw/lv_img_decoder.c b/src/lv_draw/lv_img_decoder.c index 730739c16..f6445cf55 100644 --- a/src/lv_draw/lv_img_decoder.c +++ b/src/lv_draw/lv_img_decoder.c @@ -7,6 +7,7 @@ * INCLUDES *********************/ #include "lv_img_decoder.h" +#include "../lv_core/lv_refr.h" #include "../lv_draw/lv_draw_img.h" #include "../lv_misc/lv_ll.h" #include "../lv_misc/lv_color.h" @@ -31,6 +32,7 @@ typedef struct lv_fs_file_t * f; #endif lv_color_t * palette; + lv_opa_t * opa; } lv_img_decoder_built_in_data_t; /********************** @@ -375,7 +377,8 @@ lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder lv_img_decoder_built_in_data_t * user_data = dsc->user_data; user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t)); - if(user_data->palette == NULL) { + user_data->opa = lv_mem_alloc(palette_size * sizeof(lv_opa_t)); + if(user_data->palette == NULL || user_data->opa == NULL) { LV_LOG_ERROR("img_decoder_built_in_open: out of memory"); #if LV_USE_FILESYSTEM lv_mem_assert(user_data->f); @@ -386,7 +389,13 @@ lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder /*Read the palette from file*/ #if LV_USE_FILESYSTEM lv_fs_seek(user_data->f, 4); /*Skip the header*/ - lv_fs_read(user_data->f, user_data->palette, palette_size * sizeof(lv_color_t), NULL); + lv_color32_t cur_color; + uint32_t i; + for(i = 0; i < palette_size; i++) { + lv_fs_read(user_data->f, &cur_color, sizeof(lv_color32_t), NULL); + user_data->palette[i] = lv_color_make(cur_color.ch.red, cur_color.ch.green, cur_color.ch.blue); + user_data->opa[i] = cur_color.ch.alpha; + } #else LV_LOG_WARN("Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0"); return LV_RES_INV; @@ -398,9 +407,21 @@ lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder uint32_t i; for(i = 0; i < palette_size; i++) { user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue); + user_data->opa[i] = palette_p[i].ch.alpha; } } +#if LV_INDEXED_CHROMA + /* Set the chroma color to transparent. */ + lv_disp_t * disp = lv_refr_get_disp_refreshing(); + uint32_t i; + for(i = 0; i < palette_size; i++) { + if(user_data->palette[i].full == disp->driver.color_chroma_key.full) { + user_data->opa[i] = 0; + } + } +#endif + dsc->img_data = NULL; return LV_RES_OK; #else @@ -705,7 +726,20 @@ static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_color_t * cbuf = (lv_color_t *)buf; for(i = 0; i < len; i++) { val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; - cbuf[i] = user_data->palette[val_act]; + + lv_color_t color = user_data->palette[val_act]; +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full & 0xFF; + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (color.full >> 8) & 0xFF; +#elif LV_COLOR_DEPTH == 32 + *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = color.full; +#else +#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" +#endif + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = user_data->opa[val_act]; pos -= px_size; if(pos < 0) { From 54a9ea617910bfd71d73d7370d5a6d145b73f8bc Mon Sep 17 00:00:00 2001 From: tgillbe Date: Wed, 28 Aug 2019 15:07:17 +0100 Subject: [PATCH 38/49] Action review comments --- src/lv_draw/lv_draw_img.c | 10 +++++++++- src/lv_draw/lv_img_decoder.c | 16 +--------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 65d54703d..0a92ac314 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -401,7 +401,15 @@ bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) switch(cf) { case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: - case LV_IMG_CF_RAW_CHROMA_KEYED: is_chroma_keyed = true; break; + case LV_IMG_CF_RAW_CHROMA_KEYED: +#if LV_INDEXED_CHROMA + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_INDEXED_8BIT: +#endif + is_chroma_keyed = true; break; + default: is_chroma_keyed = false; break; } diff --git a/src/lv_draw/lv_img_decoder.c b/src/lv_draw/lv_img_decoder.c index f6445cf55..cd53d3934 100644 --- a/src/lv_draw/lv_img_decoder.c +++ b/src/lv_draw/lv_img_decoder.c @@ -7,7 +7,6 @@ * INCLUDES *********************/ #include "lv_img_decoder.h" -#include "../lv_core/lv_refr.h" #include "../lv_draw/lv_draw_img.h" #include "../lv_misc/lv_ll.h" #include "../lv_misc/lv_color.h" @@ -411,17 +410,6 @@ lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder } } -#if LV_INDEXED_CHROMA - /* Set the chroma color to transparent. */ - lv_disp_t * disp = lv_refr_get_disp_refreshing(); - uint32_t i; - for(i = 0; i < palette_size; i++) { - if(user_data->palette[i].full == disp->driver.color_chroma_key.full) { - user_data->opa[i] = 0; - } - } -#endif - dsc->img_data = NULL; return LV_RES_OK; #else @@ -720,12 +708,10 @@ static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, #endif } - uint8_t byte_act = 0; uint8_t val_act; lv_coord_t i; - lv_color_t * cbuf = (lv_color_t *)buf; for(i = 0; i < len; i++) { - val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + val_act = (*data_tmp & (mask << pos)) >> pos; lv_color_t color = user_data->palette[val_act]; #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 From b1047f4b59254c0a89ab0e8d780dc56905445b00 Mon Sep 17 00:00:00 2001 From: Themba Dube Date: Wed, 28 Aug 2019 18:53:30 -0400 Subject: [PATCH 39/49] ddlist: move arrow to other side if right alignment is used --- src/lv_objx/lv_ddlist.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lv_objx/lv_ddlist.c b/src/lv_objx/lv_ddlist.c index 3deeed174..faf21752b 100644 --- a/src/lv_objx/lv_ddlist.c +++ b/src/lv_objx/lv_ddlist.c @@ -580,9 +580,14 @@ static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_desig new_style.text.color = sel_style->text.color; new_style.text.opa = sel_style->text.opa; lv_area_t area_arrow; - area_arrow.x2 = ddlist->coords.x2 - style->body.padding.right; - area_arrow.x1 = area_arrow.x2 - - lv_txt_get_width(LV_SYMBOL_DOWN, strlen(LV_SYMBOL_DOWN), sel_style->text.font, 0, 0); + lv_coord_t arrow_width = lv_txt_get_width(LV_SYMBOL_DOWN, strlen(LV_SYMBOL_DOWN), sel_style->text.font, 0, 0); + if(lv_label_get_align(ext->label) != LV_LABEL_ALIGN_RIGHT) { + area_arrow.x2 = ddlist->coords.x2 - style->body.padding.right; + area_arrow.x1 = area_arrow.x2 - arrow_width; + } else { + area_arrow.x1 = ddlist->coords.x1 + style->body.padding.left; + area_arrow.x2 = area_arrow.x1 + arrow_width; + } area_arrow.y1 = ddlist->coords.y1 + style->text.line_space; area_arrow.y2 = area_arrow.y1 + font_h; From 78125b66db29d6ee7edcaaf330bc16c8c92afa25 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 30 Aug 2019 10:59:04 +0200 Subject: [PATCH 40/49] Update lv_version.h --- src/lv_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_version.h b/src/lv_version.h index 745a7e595..c447d5620 100644 --- a/src/lv_version.h +++ b/src/lv_version.h @@ -16,7 +16,7 @@ extern "C" { /*Current version of LittlevGL*/ #define LVGL_VERSION_MAJOR 6 #define LVGL_VERSION_MINOR 0 -#define LVGL_VERSION_PATCH 0 +#define LVGL_VERSION_PATCH 2 #define LVGL_VERSION_INFO "" From 8efba7607390880d27bea7d7a1d7dc210da46fe8 Mon Sep 17 00:00:00 2001 From: Deon Marais Date: Sun, 1 Sep 2019 15:19:14 +0200 Subject: [PATCH 41/49] Make sin table constant in lv_math.c (#1185) --- src/lv_misc/lv_math.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_misc/lv_math.c b/src/lv_misc/lv_math.c index d16a16a4b..ea332b61b 100644 --- a/src/lv_misc/lv_math.c +++ b/src/lv_misc/lv_math.c @@ -25,7 +25,7 @@ /********************** * STATIC VARIABLES **********************/ -static int16_t sin0_90_table[] = { +static const int16_t sin0_90_table[] = { 0, 572, 1144, 1715, 2286, 2856, 3425, 3993, 4560, 5126, 5690, 6252, 6813, 7371, 7927, 8481, 9032, 9580, 10126, 10668, 11207, 11743, 12275, 12803, 13328, 13848, 14364, 14876, 15383, 15886, 16383, 16876, 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621, 21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, From 49c2bbedbbfcbfd98e2fd99c37092af91ac8347d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 3 Sep 2019 13:53:56 -0400 Subject: [PATCH 42/49] Fix alpha indexed images with 1 bit color depth (#1184) --- src/lv_draw/lv_draw_img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 0a92ac314..eacaa2d23 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -575,7 +575,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas else { lv_coord_t width = lv_area_get_width(&mask_com); - uint8_t * buf = lv_draw_get_buf(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1)); /*+1 because of the possible alpha byte*/ + uint8_t * buf = lv_draw_get_buf(lv_area_get_width(&mask_com) * LV_IMG_PX_SIZE_ALPHA_BYTE); /*space for the possible alpha byte*/ lv_area_t line; lv_area_copy(&line, &mask_com); From ffd4708ac3b6a537d13c7a538b722477584f4230 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 4 Sep 2019 15:58:05 +0200 Subject: [PATCH 43/49] Remove survey --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index a90532560..d07a5b680 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,6 @@

- -

Shape the future of LittlevGL

- -

- -

- -

-It takes only 5 minutes to tell some information about how you use LittlevGL, what you like about it, what should be improved and the future directions you find reasonable. -

- ----

From eefd9c4e0d0d434aa08c658db9c1f397e87804c6 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 4 Sep 2019 16:06:59 +0200 Subject: [PATCH 44/49] lv_table: fix crash on copy in lv_table_create --- src/lv_objx/lv_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lv_objx/lv_table.c b/src/lv_objx/lv_table.c index ec8ebe5b8..ab0e47879 100644 --- a/src/lv_objx/lv_table.c +++ b/src/lv_objx/lv_table.c @@ -106,8 +106,8 @@ lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy) ext->cell_style[1] = copy_ext->cell_style[1]; ext->cell_style[2] = copy_ext->cell_style[2]; ext->cell_style[3] = copy_ext->cell_style[3]; - ext->col_cnt = copy_ext->col_cnt; - ext->row_cnt = copy_ext->row_cnt; + lv_table_set_row_cnt(new_table, copy_ext->row_cnt); + lv_table_set_col_cnt(new_table, copy_ext->col_cnt); /*Refresh the style with new signal function*/ lv_obj_refresh_style(new_table); From 8e5e33d746aff857943283e0988121bfad766c59 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 12 Sep 2019 15:25:42 +0200 Subject: [PATCH 45/49] add lv_slider_set/get_sym --- src/lv_objx/lv_slider.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/lv_objx/lv_slider.h | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/lv_objx/lv_slider.c b/src/lv_objx/lv_slider.c index a7fb4333b..6a067f841 100644 --- a/src/lv_objx/lv_slider.c +++ b/src/lv_objx/lv_slider.c @@ -316,6 +316,8 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig /*If dragged draw to the drag position*/ if(ext->drag_value != LV_SLIDER_NOT_PRESSED) cur_value = ext->drag_value; + bool sym = false; + if(ext->bar.sym && ext->bar.min_value < 0 && ext->bar.max_value > 0) sym = true; if(slider_w >= slider_h) { lv_coord_t indic_w = lv_area_get_width(&area_indic); @@ -335,7 +337,19 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig { area_indic.x2 = (int32_t)((int32_t)indic_w * (cur_value - min_value)) / (max_value - min_value); } + area_indic.x2 = area_indic.x1 + area_indic.x2 - 1; + if(sym) { + /*Calculate the coordinate of the zero point*/ + lv_coord_t zero; + zero = area_indic.x1 + (-ext->bar.min_value * slider_w) / (ext->bar.max_value - ext->bar.min_value); + if(area_indic.x2 > zero) + area_indic.x1 = zero; + else { + area_indic.x1 = area_indic.x2; + area_indic.x2 = zero; + } + } /*Draw the indicator but don't draw an ugly 1px wide rectangle on the left on min. * value*/ @@ -359,8 +373,21 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig { area_indic.y1 = (int32_t)((int32_t)indic_h * (cur_value - min_value)) / (max_value - min_value); } + area_indic.y1 = area_indic.y2 - area_indic.y1 + 1; + if(sym) { + /*Calculate the coordinate of the zero point*/ + lv_coord_t zero; + zero = area_indic.y2 - (-ext->bar.min_value * slider_h) / (ext->bar.max_value - ext->bar.min_value); + if(area_indic.y1 < zero) + area_indic.y2 = zero; + else { + area_indic.y2 = area_indic.y1; + area_indic.y1 = zero; + } + } + /*Draw the indicator but don't draw an ugly 1px height rectangle on the bottom on min. * value*/ if(area_indic.x1 != area_indic.x2) lv_draw_rect(&area_indic, mask, style_indic, opa_scale); @@ -386,7 +413,12 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig if(slider_w >= slider_h) { if(ext->knob_in == 0) { - knob_area.x1 = area_indic.x2 - slider_h / 2; + if(sym == false) { + knob_area.x1 = area_indic.x2 - slider_h / 2; + } else { + if(cur_value > 0) knob_area.x1 = area_indic.x2 - slider_h / 2; + else knob_area.x1 = area_indic.x1 - slider_h / 2; + } knob_area.x2 = knob_area.x1 + slider_h - 1; } else { #if LV_USE_ANIMATION @@ -415,7 +447,12 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig knob_area.y2 = slider->coords.y2; } else { if(ext->knob_in == 0) { - knob_area.y1 = area_indic.y1 - slider_w / 2; + if(sym == false) { + knob_area.y1 = area_indic.y1 - slider_w / 2; + } else { + if(cur_value > 0) knob_area.y1 = area_indic.y1 - slider_w / 2; + else knob_area.y1 = area_indic.y2 - slider_w / 2; + } knob_area.y2 = knob_area.y1 + slider_w - 1; } else { #if LV_USE_ANIMATION diff --git a/src/lv_objx/lv_slider.h b/src/lv_objx/lv_slider.h index 07086efe4..967c8b688 100644 --- a/src/lv_objx/lv_slider.h +++ b/src/lv_objx/lv_slider.h @@ -93,15 +93,26 @@ static inline void lv_slider_set_range(lv_obj_t * slider, int16_t min, int16_t m } /** - * Set the animation time of the slider - * @param slider pointer to a bar object - * @param anim_time the animation time in milliseconds. + * Make the slider symmetric to zero. The indicator will grow from zero instead of the minimum + * position. + * @param slider pointer to a slider object + * @param en true: enable disable symmetric behavior; false: disable */ static inline void lv_slider_set_anim_time(lv_obj_t * slider, uint16_t anim_time) { lv_bar_set_anim_time(slider, anim_time); } +/** + * Set the animation time of the slider + * @param slider pointer to a bar object + * @param anim_time the animation time in milliseconds. + */ +static inline void lv_slider_set_sym(lv_obj_t * slider, bool en) +{ + lv_bar_set_sym(slider, en); +} + /** * Set the 'knob in' attribute of a slider * @param slider pointer to slider object @@ -156,6 +167,26 @@ static inline int16_t lv_slider_get_max_value(const lv_obj_t * slider) */ bool lv_slider_is_dragged(const lv_obj_t * slider); +/** + * Get the animation time of the slider + * @param slider pointer to a slider object + * @return the animation time in milliseconds. + */ +static inline uint16_t lv_slider_get_anim_time(lv_obj_t * slider) +{ + return lv_bar_get_anim_time(slider); +} + +/** + * Get whether the slider is symmetric or not. + * @param slider pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +static inline bool lv_slider_get_sym(lv_obj_t * slider) +{ + return lv_bar_get_sym(slider); +} + /** * Get the 'knob in' attribute of a slider * @param slider pointer to slider object From a031af4f1ebf92722f935c54e79e930bc97af022 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 12 Sep 2019 16:04:11 +0200 Subject: [PATCH 46/49] lv_list: fix the use of last_clicked_btn --- src/lv_objx/lv_list.c | 19 +++++++++---------- src/lv_objx/lv_list.h | 3 +++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index c6e4300ca..ef50c4afe 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -47,11 +47,7 @@ static lv_signal_cb_t img_signal; static lv_signal_cb_t label_signal; static lv_signal_cb_t ancestor_page_signal; static lv_signal_cb_t ancestor_btn_signal; -#if LV_USE_GROUP -/*Used to make the last clicked button pressed (selected) when the list become focused and - * `click_focus == 1`*/ -static lv_obj_t * last_clicked_btn; -#endif + /********************** * MACROS @@ -94,6 +90,7 @@ lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy) #if LV_USE_GROUP ext->last_sel = NULL; ext->selected_btn = NULL; + ext->last_clicked_btn = NULL; #endif lv_obj_set_signal_cb(new_list, lv_list_signal); @@ -751,10 +748,12 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) /*Else select the clicked button*/ else { /*Mark the last clicked button (if any) as selected because it triggered the focus*/ - if(last_clicked_btn) { - lv_list_set_btn_selected(list, last_clicked_btn); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->last_clicked_btn) { + lv_list_set_btn_selected(list, ext->last_clicked_btn); + ext->last_clicked_btn = NULL; + } else { - lv_list_ext_t * ext = lv_obj_get_ext_attr(list); if(ext->last_sel) { /* Select the last used button */ lv_list_set_btn_selected(list, ext->last_sel); @@ -770,8 +769,8 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) #if LV_USE_GROUP /*De-select the selected btn*/ lv_list_set_btn_selected(list, NULL); - last_clicked_btn = NULL; /*button click will be set if click happens before focus*/ lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->last_clicked_btn = NULL; /*button click will be set if click happens before focus*/ ext->selected_btn = NULL; #endif } else if(sign == LV_SIGNAL_GET_EDITABLE) { @@ -861,7 +860,7 @@ static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * para /* If `click_focus == 1` then LV_SIGNAL_FOCUS need to know which button triggered the focus * to mark it as selected (pressed state)*/ - last_clicked_btn = btn; + ext->last_clicked_btn = btn; #endif if(lv_indev_is_dragging(lv_indev_get_act()) == false && ext->single_mode) { lv_list_btn_single_select(btn); diff --git a/src/lv_objx/lv_list.h b/src/lv_objx/lv_list.h index 7b7927841..5a8c6ee4c 100644 --- a/src/lv_objx/lv_list.h +++ b/src/lv_objx/lv_list.h @@ -61,6 +61,9 @@ typedef struct #if LV_USE_GROUP lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ lv_obj_t * selected_btn; /* The button is currently being selected*/ + /*Used to make the last clicked button pressed (selected) when the list become focused and + * `click_focus == 1`*/ + lv_obj_t * last_clicked_btn; #endif } lv_list_ext_t; From 915046d3ba498cc7ee774deb9bf3840455d7600f Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 13 Sep 2019 11:51:31 +0200 Subject: [PATCH 47/49] add font decompression and bpp=3 support --- src/lv_font/lv_font_fmt_txt.c | 156 +++++++++++++++++++++++++++++++++- src/lv_font/lv_font_fmt_txt.h | 2 +- 2 files changed, 156 insertions(+), 2 deletions(-) diff --git a/src/lv_font/lv_font_fmt_txt.c b/src/lv_font/lv_font_fmt_txt.c index d491da1f8..e01883b7b 100644 --- a/src/lv_font/lv_font_fmt_txt.c +++ b/src/lv_font/lv_font_fmt_txt.c @@ -11,6 +11,7 @@ #include "../lv_misc/lv_types.h" #include "../lv_misc/lv_log.h" #include "../lv_misc/lv_utils.h" +#include "../lv_misc/lv_mem.h" /********************* * DEFINES @@ -28,6 +29,7 @@ static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t static int32_t unicode_list_compare(const void * ref, const void * element); static int32_t kern_pair_8_compare(const void * ref, const void * element); static int32_t kern_pair_16_compare(const void * ref, const void * element); +static void decompress(const uint8_t * in, uint8_t * out, uint16_t px_num, uint8_t bpp); /********************** * STATIC VARIABLES @@ -59,7 +61,32 @@ const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unic const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid]; - if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index]; +// if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) { +// if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index]; +// } +// /*Handle compressed bitmap*/ +// else + { + static uint8_t * buf = NULL; + + uint32_t gsize = gdsc->box_w * gdsc->box_h; + uint32_t buf_size = gsize; + switch(fdsc->bpp) { + case 1: buf_size = gsize >> 3; break; + case 2: buf_size = gsize >> 2; break; + case 3: buf_size = gsize >> 1; break; + case 4: buf_size = gsize >> 1; break; + } + + if(lv_mem_get_size(buf) < buf_size) { + buf = lv_mem_realloc(buf, buf_size); + lv_mem_assert(buf); + if(buf == NULL) return NULL; + } + + decompress(&fdsc->glyph_bitmap[gdsc->bitmap_index], buf, gdsc->box_w * gdsc->box_h, fdsc->bpp); + return buf; + } /*If not returned earlier then the letter is not found in this font*/ return NULL; @@ -238,6 +265,133 @@ static int32_t kern_pair_16_compare(const void * ref, const void * element) else return (int32_t) ref16_p[1] - element16_p[1]; } + + +/** + * Read bits from an input buffer. The read can cross byte boundary. + * @param in the input buffer to read from. + * @param bit_pos index of teh first bit to read. + * @param len number of bits to read (must be <= 8). + * @return the read bits + */ +static uint8_t get_bits(const uint8_t * in, uint32_t bit_pos, uint8_t len) +{ + uint8_t res = 0; + uint32_t byte_pos = bit_pos >> 3; + bit_pos = bit_pos & 0x7; + uint8_t bit_mask = (uint16_t)((uint16_t) 1 << len) - 1; + uint16_t in16 = (in[byte_pos] << 8) + in[byte_pos + 1]; + + res = (in16 >> (16 - bit_pos - len)) & bit_mask; + return res; +} + +/** + * Write `val` data to `bit_pos` position of `out`. The write can NOT cross byte boundary. + * @param out buffer where to write + * @param bit_pos bit index to write + * @param val value to write + * @param len length of bits to write from `val`. (Counted from the LSB). + * @note `len == 3` will be converted to `len = 4` and `val` will be upscaled too + */ +static void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len) +{ + if(len == 3) { + len = 4; + switch(val) { + case 0: val = 0; break; + case 1: val = 2; break; + case 2: val = 4; break; + case 3: val = 6; break; + case 4: val = 9; break; + case 5: val = 11; break; + case 6: val = 13; break; + case 7: val = 15; break; + } + } + + uint16_t byte_pos = bit_pos >> 3; + bit_pos = bit_pos & 0x7; + bit_pos = 8 - bit_pos - len; + + uint8_t bit_mask = (uint16_t)((uint16_t) 1 << len) - 1; + out[byte_pos] &= ((~bit_mask) << bit_pos); + out[byte_pos] |= (val << bit_pos); +} + +/** + * The compress a glyph's bitmap + * @param in the compressed bitmap + * @param out buffer to store the result + * @param px_num number of pixels in the glyph (width * height) + * @param bpp bit per pixel (bpp = 3 will be converted to bpp = 4) + */ +static void decompress(const uint8_t * in, uint8_t * out, uint16_t px_num, uint8_t bpp) +{ + uint32_t rdp = 0; + uint32_t wrp = 0; + uint16_t px_cnt = 0; + uint8_t wr_size = bpp; + if(bpp == 3) wr_size = 4; + + uint8_t act_val = get_bits(in, rdp, bpp); + rdp += bpp; + + while(px_cnt < px_num) { + + bits_write(out, wrp, act_val, bpp); + wrp += wr_size; + px_cnt ++; + + uint8_t next_val = get_bits(in, rdp, bpp); + rdp += bpp; + + /*If the new value is different the it's simply the next pixel*/ + if(act_val != next_val) { + act_val = next_val; + } + /*If the next px is the same the this pixel will be repeated */ + else { + bits_write(out, wrp, next_val, bpp); + wrp += wr_size; + px_cnt ++; + + uint8_t i; + for(i = 0; i < 11; i++) { + uint8_t r; + r = get_bits(in, rdp, 1); + rdp++; + + if(r == 1) { + if(i != 10) { /*Ignore the 11th '1'*/ + bits_write(out, wrp, next_val, bpp); + wrp += wr_size; + px_cnt++; + } + } + else break; /*Zero closes the repeats*/ + } + + /*After 11 repeats a 6 bit counter comes*/ + if(i == 11) { + uint8_t cnt = get_bits(in, rdp, 6); + rdp += 6; + + uint8_t i; + for(i = 0; i < cnt; i++) { + bits_write(out, wrp, next_val, bpp); + wrp += wr_size; + px_cnt ++; + } + } + + /*Preload the next pixel*/ + act_val = get_bits(in, rdp, bpp); + rdp += bpp; + } + } +} + /** Code Comparator. * * Compares the value of both input arguments. diff --git a/src/lv_font/lv_font_fmt_txt.h b/src/lv_font/lv_font_fmt_txt.h index 446a1067d..0fd41347b 100644 --- a/src/lv_font/lv_font_fmt_txt.h +++ b/src/lv_font/lv_font_fmt_txt.h @@ -180,7 +180,7 @@ typedef struct { /*Number of cmap tables*/ uint16_t cmap_num :10; - /*Bit per pixel: 1, 2, 4 or 8*/ + /*Bit per pixel: 1, 2, 3, 4*/ uint16_t bpp :3; /*Type of `kern_dsc`*/ From f190c781959c4cf65cbfaff2a6864d306cc10ba6 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 13 Sep 2019 15:40:12 +0200 Subject: [PATCH 48/49] font compression: add prefilter support --- src/lv_core/lv_obj.c | 2 +- src/lv_draw/lv_draw_basic.c | 3 + src/lv_font/lv_font_fmt_txt.c | 199 ++++++++++++++++++++++------------ 3 files changed, 135 insertions(+), 69 deletions(-) diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index e0ad6c42c..bb7b81299 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -319,7 +319,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->realign.auto_realign = copy->realign.auto_realign; #endif - /*Only copy the `event_cb`. `signal_cb` and `design_cb` will be copied the the derived + /*Only copy the `event_cb`. `signal_cb` and `design_cb` will be copied in the derived * object type (e.g. `lv_btn`)*/ new_obj->event_cb = copy->event_cb; diff --git a/src/lv_draw/lv_draw_basic.c b/src/lv_draw/lv_draw_basic.c index afbf481df..bbe61e512 100644 --- a/src/lv_draw/lv_draw_basic.c +++ b/src/lv_draw/lv_draw_basic.c @@ -259,6 +259,9 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv uint8_t bitmask_init; uint8_t bitmask; + /*bpp = 3 should be converted to bpp = 4 in lv_font_get_glyph_bitmap */ + if(g.bpp == 3) g.bpp = 4; + switch(g.bpp) { case 1: bpp_opa_table = bpp1_opa_table; diff --git a/src/lv_font/lv_font_fmt_txt.c b/src/lv_font/lv_font_fmt_txt.c index e01883b7b..c52c4490a 100644 --- a/src/lv_font/lv_font_fmt_txt.c +++ b/src/lv_font/lv_font_fmt_txt.c @@ -8,6 +8,7 @@ *********************/ #include "lv_font.h" #include "lv_font_fmt_txt.h" +#include "../lv_draw/lv_draw.h" #include "../lv_misc/lv_types.h" #include "../lv_misc/lv_log.h" #include "../lv_misc/lv_utils.h" @@ -20,6 +21,11 @@ /********************** * TYPEDEFS **********************/ +typedef enum { + RLE_STATE_SINGLE = 0, + RLE_STATE_REPEATE, + RLE_STATE_COUNTER, +}rle_state_t; /********************** * STATIC PROTOTYPES @@ -29,12 +35,26 @@ static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t static int32_t unicode_list_compare(const void * ref, const void * element); static int32_t kern_pair_8_compare(const void * ref, const void * element); static int32_t kern_pair_16_compare(const void * ref, const void * element); -static void decompress(const uint8_t * in, uint8_t * out, uint16_t px_num, uint8_t bpp); + +static void decompress(const uint8_t * in, uint8_t * out, lv_coord_t w, lv_coord_t h, uint8_t bpp); +static void decompress_line(uint8_t * out, lv_coord_t w); +static uint8_t get_bits(const uint8_t * in, uint32_t bit_pos, uint8_t len); +static void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len); +static void rle_init(const uint8_t * in, uint8_t bpp); +static uint8_t rle_next(void); + /********************** * STATIC VARIABLES **********************/ +static uint32_t rle_rdp; +static const uint8_t * rle_in; +static uint8_t rle_bpp; +static uint8_t rle_prev_v; +static uint8_t rle_cnt; +static rle_state_t rle_state; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -61,11 +81,11 @@ const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unic const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid]; -// if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) { -// if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index]; -// } -// /*Handle compressed bitmap*/ -// else + if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) { + if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index]; + } + /*Handle compressed bitmap*/ + else { static uint8_t * buf = NULL; @@ -84,7 +104,7 @@ const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unic if(buf == NULL) return NULL; } - decompress(&fdsc->glyph_bitmap[gdsc->bitmap_index], buf, gdsc->box_w * gdsc->box_h, fdsc->bpp); + decompress(&fdsc->glyph_bitmap[gdsc->bitmap_index], buf, gdsc->box_w , gdsc->box_h, fdsc->bpp); return buf; } @@ -265,7 +285,57 @@ static int32_t kern_pair_16_compare(const void * ref, const void * element) else return (int32_t) ref16_p[1] - element16_p[1]; } +/** + * The compress a glyph's bitmap + * @param in the compressed bitmap + * @param out buffer to store the result + * @param px_num number of pixels in the glyph (width * height) + * @param bpp bit per pixel (bpp = 3 will be converted to bpp = 4) + */ +static void decompress(const uint8_t * in, uint8_t * out, lv_coord_t w, lv_coord_t h, uint8_t bpp) +{ + uint32_t wrp = 0; + uint8_t wr_size = bpp; + if(bpp == 3) wr_size = 4; + rle_init(in, bpp); + + uint8_t * line_buf = lv_draw_get_buf(w * 2); + uint8_t * line_buf1 = line_buf; + uint8_t * line_buf2 = line_buf + w; + + decompress_line(line_buf1, w); + + lv_coord_t y; + lv_coord_t x; + for(x = 0; x < w; x++) { + bits_write(out,wrp, line_buf1[x], bpp); + wrp += wr_size; + } + + for(y = 1; y < h; y++) { + decompress_line(line_buf2, w); + + for(x = 0; x < w; x++) { + line_buf1[x] = line_buf2[x] ^ line_buf1[x]; + bits_write(out,wrp, line_buf1[x], bpp); + wrp += wr_size; + } + } +} + +/** + * Decompress one line. Store one pixel per byte + * @param out output buffer + * @param w width of the line in pixel count + */ +static void decompress_line(uint8_t * out, lv_coord_t w) +{ + lv_coord_t i; + for(i = 0; i < w; i++) { + out[i] = rle_next(); + } +} /** * Read bits from an input buffer. The read can cross byte boundary. @@ -319,77 +389,70 @@ static void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len out[byte_pos] |= (val << bit_pos); } -/** - * The compress a glyph's bitmap - * @param in the compressed bitmap - * @param out buffer to store the result - * @param px_num number of pixels in the glyph (width * height) - * @param bpp bit per pixel (bpp = 3 will be converted to bpp = 4) - */ -static void decompress(const uint8_t * in, uint8_t * out, uint16_t px_num, uint8_t bpp) +static void rle_init(const uint8_t * in, uint8_t bpp) { - uint32_t rdp = 0; - uint32_t wrp = 0; - uint16_t px_cnt = 0; - uint8_t wr_size = bpp; - if(bpp == 3) wr_size = 4; + rle_in = in; + rle_bpp = bpp; + rle_state = RLE_STATE_SINGLE; + rle_rdp = 0; + rle_prev_v = 0; + rle_cnt = 0; +} - uint8_t act_val = get_bits(in, rdp, bpp); - rdp += bpp; +static uint8_t rle_next(void) +{ + uint8_t v = 0; + uint8_t ret = 0; - while(px_cnt < px_num) { - - bits_write(out, wrp, act_val, bpp); - wrp += wr_size; - px_cnt ++; - - uint8_t next_val = get_bits(in, rdp, bpp); - rdp += bpp; - - /*If the new value is different the it's simply the next pixel*/ - if(act_val != next_val) { - act_val = next_val; + if(rle_state == RLE_STATE_SINGLE) { + ret = get_bits(rle_in, rle_rdp, rle_bpp); + if(rle_rdp != 0 && rle_prev_v == ret) { + rle_cnt = 0; + rle_state = RLE_STATE_REPEATE; } - /*If the next px is the same the this pixel will be repeated */ - else { - bits_write(out, wrp, next_val, bpp); - wrp += wr_size; - px_cnt ++; - uint8_t i; - for(i = 0; i < 11; i++) { - uint8_t r; - r = get_bits(in, rdp, 1); - rdp++; - - if(r == 1) { - if(i != 10) { /*Ignore the 11th '1'*/ - bits_write(out, wrp, next_val, bpp); - wrp += wr_size; - px_cnt++; - } - } - else break; /*Zero closes the repeats*/ - } - - /*After 11 repeats a 6 bit counter comes*/ - if(i == 11) { - uint8_t cnt = get_bits(in, rdp, 6); - rdp += 6; - - uint8_t i; - for(i = 0; i < cnt; i++) { - bits_write(out, wrp, next_val, bpp); - wrp += wr_size; - px_cnt ++; + rle_prev_v = ret; + rle_rdp += rle_bpp; + } + else if(rle_state == RLE_STATE_REPEATE) { + v = get_bits(rle_in, rle_rdp, 1); + rle_cnt++; + rle_rdp += 1; + if(v == 1) { + ret = rle_prev_v; + if(rle_cnt == 11) { + rle_cnt = get_bits(rle_in, rle_rdp, 6); + rle_rdp += 6; + if(rle_cnt != 0) { + rle_state = RLE_STATE_COUNTER; + } else { + ret = get_bits(rle_in, rle_rdp, rle_bpp); + rle_prev_v = ret; + rle_rdp += rle_bpp; + rle_state = RLE_STATE_SINGLE; } } + } else { + ret = get_bits(rle_in, rle_rdp, rle_bpp); + rle_prev_v = ret; + rle_rdp += rle_bpp; + rle_state = RLE_STATE_SINGLE; + } - /*Preload the next pixel*/ - act_val = get_bits(in, rdp, bpp); - rdp += bpp; + + } + else if(rle_state == RLE_STATE_COUNTER) { + ret = rle_prev_v; + rle_cnt--; + if(rle_cnt == 0) { + ret = get_bits(rle_in, rle_rdp, rle_bpp); + rle_prev_v = ret; + rle_rdp += rle_bpp; + rle_state = RLE_STATE_SINGLE; } } + + return ret; } /** Code Comparator. From 88bda09f5f1f1c25c6e675e5cb689e3a9008d4ab Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 14 Sep 2019 11:24:48 +0200 Subject: [PATCH 49/49] btnm: fix keyboard navigation --- src/lv_objx/lv_btnm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lv_objx/lv_btnm.c b/src/lv_objx/lv_btnm.c index f9b83b6cf..cf3b882ae 100644 --- a/src/lv_objx/lv_btnm.c +++ b/src/lv_objx/lv_btnm.c @@ -863,7 +863,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param) for(area_below = ext->btn_id_pr; area_below < ext->btn_cnt; area_below++) { if(ext->button_areas[area_below].y1 > ext->button_areas[ext->btn_id_pr].y1 && pr_center >= ext->button_areas[area_below].x1 && - pr_center <= ext->button_areas[area_below].x2 + style->body.padding.left) { + pr_center <= ext->button_areas[area_below].x2 + style->body.padding.inner) { break; } } @@ -884,7 +884,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param) for(area_above = ext->btn_id_pr; area_above >= 0; area_above--) { if(ext->button_areas[area_above].y1 < ext->button_areas[ext->btn_id_pr].y1 && - pr_center >= ext->button_areas[area_above].x1 - style->body.padding.left && + pr_center >= ext->button_areas[area_above].x1 - style->body.padding.inner && pr_center <= ext->button_areas[area_above].x2) { break; }