mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
update bar, slider, sw drawing
This commit is contained in:
commit
31c628f332
@ -2,7 +2,9 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/littlevgl/lvgl/blob/master/LICENCE.txt"><img src="https://img.shields.io/badge/licence-MIT-blue.svg"></a>
|
||||
<a href="https://github.com/littlevgl/lvgl/releases/tag/v6.0"><img src="https://img.shields.io/badge/version-6.0-blue.svg"></a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://littlevgl.com/github/cover_ori_reduced_2.gif">
|
||||
</p>
|
||||
|
||||
@ -130,7 +132,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;
|
||||
|
@ -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 '_'
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "lvgl",
|
||||
"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":
|
||||
|
@ -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
|
||||
|
||||
@ -297,6 +300,23 @@ 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
|
||||
# define LV_SPRINTF_INCLUDE <stdio.h>
|
||||
# define lv_snprintf snprintf
|
||||
# define lv_vsnprintf vsnprintf
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
/*===================
|
||||
* LV_OBJ SETTINGS
|
||||
*==================*/
|
||||
|
@ -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
|
||||
@ -412,6 +417,37 @@
|
||||
#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
|
||||
#endif
|
||||
#if LV_SPRINTF_CUSTOM
|
||||
#ifndef LV_SPRINTF_INCLUDE
|
||||
# define LV_SPRINTF_INCLUDE <stdio.h>
|
||||
#endif
|
||||
#ifndef lv_snprintf
|
||||
# define lv_snprintf snprintf
|
||||
#endif
|
||||
#ifndef lv_vsnprintf
|
||||
# define lv_vsnprintf vsnprintf
|
||||
#endif
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
/*===================
|
||||
* LV_OBJ SETTINGS
|
||||
*==================*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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;
|
||||
|
@ -320,7 +320,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;
|
||||
|
||||
|
@ -288,6 +288,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
|
||||
|
@ -99,17 +99,14 @@ void lv_draw_buf_release(void * p)
|
||||
void lv_draw_buf_free_all(void)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t s = 0;
|
||||
for(i = 0; i < LV_DRAW_BUF_MAX_NUM; i++) {
|
||||
if(_lv_draw_buf[i].p) {
|
||||
s+= _lv_draw_buf[i].size;
|
||||
lv_mem_free(_lv_draw_buf[i].p);
|
||||
_lv_draw_buf[i].p = NULL;
|
||||
_lv_draw_buf[i].used = 0;
|
||||
_lv_draw_buf[i].size = 0;
|
||||
}
|
||||
}
|
||||
if(s) printf("draf_buf free %d bytes\n", s);
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "../lv_hal/lv_hal_disp.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -406,10 +407,14 @@ 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:
|
||||
#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: is_chroma_keyed = true; break;
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
#endif
|
||||
is_chroma_keyed = true; break;
|
||||
|
||||
default: is_chroma_keyed = false; break;
|
||||
}
|
||||
|
||||
@ -428,6 +433,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:
|
||||
@ -469,6 +478,66 @@ 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)
|
||||
{
|
||||
/* 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));
|
||||
|
||||
/* 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);
|
||||
return NULL;
|
||||
}
|
||||
memset((uint8_t *)dsc->data, 0, dsc->data_size);
|
||||
|
||||
/* Fill in header */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
**********************/
|
||||
@ -510,7 +579,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_buf_get(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1)); /*+1 because of the possible alpha byte*/
|
||||
uint8_t * buf = lv_draw_buf_get(lv_area_get_width(&mask_com) * LV_IMG_PX_SIZE_ALPHA_BYTE); /*+1 because of the possible alpha byte*/
|
||||
|
||||
lv_area_t line;
|
||||
lv_area_copy(&line, &mask_com);
|
||||
|
@ -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
|
||||
**********************/
|
||||
@ -120,9 +140,30 @@ 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);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -306,6 +306,8 @@ static void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area
|
||||
uint8_t bitmask_init;
|
||||
uint8_t bitmask;
|
||||
|
||||
if(g.bpp == 3) g.bpp = 4;
|
||||
|
||||
switch(g.bpp) {
|
||||
case 1:
|
||||
bpp_opa_table = bpp1_opa_table;
|
||||
|
@ -112,12 +112,11 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
/*Most simple case: just a plain rectangle*/
|
||||
if(simple_mode && rout == 0 && style->body.main_color.full == style->body.grad_color.full) {
|
||||
lv_blend_fill(clip, coords,
|
||||
style->body.main_color, NULL, LV_DRAW_MASK_RES_FULL_COVER, style->body.opa,
|
||||
style->body.main_color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa,
|
||||
style->body.blend_mode);
|
||||
}
|
||||
/*More complex case: there is a radius, gradient or mask.*/
|
||||
else {
|
||||
|
||||
lv_draw_mask_param_t mask_rout_param;
|
||||
if(rout > 0) {
|
||||
lv_draw_mask_radius_init(&mask_rout_param, coords, rout, false);
|
||||
@ -184,7 +183,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
fill_area2.y2 = fill_area.y2;
|
||||
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
grad_color, mask_buf, mask_res, style->body.opa, style->body.blend_mode);
|
||||
grad_color, mask_buf, mask_res, opa, style->body.blend_mode);
|
||||
|
||||
|
||||
/*Central part*/
|
||||
@ -192,7 +191,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
fill_area2.x2 = coords->x2 - rout;
|
||||
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
grad_color, NULL, LV_DRAW_MASK_RES_FULL_COVER, style->body.opa, style->body.blend_mode);
|
||||
grad_color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, style->body.blend_mode);
|
||||
|
||||
fill_area2.x1 = coords->x2 - rout + 1;
|
||||
fill_area2.x2 = coords->x2;
|
||||
@ -200,7 +199,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
lv_coord_t mask_ofs = (coords->x2 - rout + 1) - (vdb->area.x1 + draw_area.x1);
|
||||
if(mask_ofs < 0) mask_ofs = 0;
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
grad_color, mask_buf + mask_ofs, mask_res, style->body.opa, style->body.blend_mode);
|
||||
grad_color, mask_buf + mask_ofs, mask_res, opa, style->body.blend_mode);
|
||||
} else {
|
||||
if(grad_map == NULL) {
|
||||
lv_blend_fill(clip, &fill_area,
|
||||
@ -270,14 +269,14 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
fill_area2.x2 = coords->x1 + rout - 1;
|
||||
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
style->body.border.color, mask_buf, mask_res, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, mask_buf, mask_res, opa, style->body.border.blend_mode);
|
||||
|
||||
if(fill_area2.y2 < coords->y1 + style->body.border.width) {
|
||||
fill_area2.x1 = coords->x1 + rout;
|
||||
fill_area2.x2 = coords->x2 - rout;
|
||||
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, style->body.border.blend_mode);
|
||||
}
|
||||
|
||||
fill_area2.x1 = coords->x2 - rout + 1;
|
||||
@ -286,7 +285,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
lv_coord_t mask_ofs = (coords->x2 - rout + 1) - (vdb->area.x1 + draw_area.x1);
|
||||
if(mask_ofs < 0) mask_ofs = 0;
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
style->body.border.color, mask_buf + mask_ofs, mask_res, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, mask_buf + mask_ofs, mask_res, opa, style->body.border.blend_mode);
|
||||
|
||||
fill_area.y1++;
|
||||
fill_area.y2++;
|
||||
@ -309,7 +308,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
fill_area2.y2 = fill_area.y2;
|
||||
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
style->body.border.color, mask_buf, mask_res, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, mask_buf, mask_res, opa, style->body.border.blend_mode);
|
||||
|
||||
|
||||
if(fill_area2.y2 > coords->y2 - style->body.border.width ) {
|
||||
@ -317,7 +316,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
fill_area2.x2 = coords->x2 - rout;
|
||||
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, style->body.border.blend_mode);
|
||||
}
|
||||
fill_area2.x1 = coords->x2 - rout + 1;
|
||||
fill_area2.x2 = coords->x2;
|
||||
@ -325,7 +324,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
lv_coord_t mask_ofs = (coords->x2 - rout + 1) - (vdb->area.x1 + draw_area.x1);
|
||||
if(mask_ofs < 0) mask_ofs = 0;
|
||||
lv_blend_fill(clip, &fill_area2,
|
||||
style->body.border.color, mask_buf + mask_ofs, mask_res, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, mask_buf + mask_ofs, mask_res, opa, style->body.border.blend_mode);
|
||||
|
||||
|
||||
fill_area.y1++;
|
||||
@ -340,14 +339,14 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
fill_area.x1 = coords->x1;
|
||||
fill_area.x2 = coords->x1 + border_width - 1;
|
||||
lv_blend_fill(clip, &fill_area,
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, style->body.border.blend_mode);
|
||||
|
||||
/*Draw the right vertical border*/
|
||||
fill_area.x1 = coords->x2 - border_width + 1;
|
||||
fill_area.x2 = coords->x2;
|
||||
|
||||
lv_blend_fill(clip, &fill_area,
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, style->body.border.blend_mode);
|
||||
}
|
||||
/*Process line by line if there is other mask too*/
|
||||
else {
|
||||
@ -360,7 +359,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
mask_res = lv_draw_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
|
||||
|
||||
lv_blend_fill( clip, &fill_area,
|
||||
style->body.border.color, mask_buf, mask_res, style->body.border.opa, style->body.border.blend_mode);
|
||||
style->body.border.color, mask_buf, mask_res, opa, style->body.border.blend_mode);
|
||||
|
||||
fill_area.y1++;
|
||||
fill_area.y2++;
|
||||
@ -496,7 +495,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, const
|
||||
|
||||
lv_coord_t ver_mid_dist = (a.y1 + corner_size) - (sh_area.y1 + lv_area_get_height(&sh_area) / 2);
|
||||
lv_coord_t ver_mid_corr = 0;
|
||||
if(ver_mid_dist < 0) ver_mid_dist = 0;
|
||||
if(ver_mid_dist <= 0) ver_mid_dist = 0;
|
||||
else {
|
||||
if(lv_area_get_height(&sh_area) & 0x1) ver_mid_corr = 1;
|
||||
}
|
||||
@ -548,7 +547,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, const
|
||||
va.y1 = sh_area.y1 + corner_size;
|
||||
va.y2 = sh_area.y2 - corner_size;
|
||||
|
||||
if(va.y1 < va.y2) {
|
||||
if(va.y1 <= va.y2) {
|
||||
for(x = a.x1; x < a.x2; x++) {
|
||||
if(x > coords->x2) {
|
||||
lv_opa_t opa_tmp = sh_buf_tmp[x - a.x1 + first_px];
|
||||
@ -602,7 +601,6 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, const
|
||||
}
|
||||
|
||||
sh_buf_tmp = sh_buf ;
|
||||
|
||||
for(y = 0; y < corner_size - ver_mid_dist + ver_mid_corr; y++) {
|
||||
memcpy(mask_buf, sh_buf_tmp, corner_size);
|
||||
mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a));
|
||||
@ -647,13 +645,15 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, const
|
||||
va.y1 = sh_area.y1 + corner_size;
|
||||
va.y2 = sh_area.y2 - corner_size;
|
||||
|
||||
for(x = a.x1; x < coords->x1; x++) {
|
||||
lv_opa_t opa_tmp = sh_buf_tmp[x - a.x1 + first_px];
|
||||
if(opa_tmp != LV_OPA_COVER || opa != LV_OPA_COVER) opa_tmp = (opa * opa_tmp) >> 8;
|
||||
lv_blend_fill(clip, &va,
|
||||
style->body.shadow.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa_tmp, style->body.shadow.blend_mode);
|
||||
va.x1++;
|
||||
va.x2++;
|
||||
if(va.y1 <= va.y2) {
|
||||
for(x = a.x1; x < coords->x1; x++) {
|
||||
lv_opa_t opa_tmp = sh_buf_tmp[x - a.x1 + first_px];
|
||||
if(opa_tmp != LV_OPA_COVER || opa != LV_OPA_COVER) opa_tmp = (opa * opa_tmp) >> 8;
|
||||
lv_blend_fill(clip, &va,
|
||||
style->body.shadow.color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa_tmp, style->body.shadow.blend_mode);
|
||||
va.x1++;
|
||||
va.x2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -31,6 +31,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 +376,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 +388,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,6 +406,7 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -700,13 +709,24 @@ 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;
|
||||
cbuf[i] = user_data->palette[val_act];
|
||||
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
|
||||
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) {
|
||||
|
@ -8,9 +8,11 @@
|
||||
*********************/
|
||||
#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"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -19,6 +21,11 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum {
|
||||
RLE_STATE_SINGLE = 0,
|
||||
RLE_STATE_REPEATE,
|
||||
RLE_STATE_COUNTER,
|
||||
}rle_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@ -29,10 +36,25 @@ 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, 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
|
||||
**********************/
|
||||
@ -59,7 +81,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 +285,178 @@ 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_buf1 = lv_draw_buf_get(w);
|
||||
uint8_t * line_buf2 = lv_draw_buf_get(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;
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_buf_release(line_buf1);
|
||||
lv_draw_buf_release(line_buf2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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);
|
||||
}
|
||||
|
||||
static void rle_init(const uint8_t * in, uint8_t bpp)
|
||||
{
|
||||
rle_in = in;
|
||||
rle_bpp = bpp;
|
||||
rle_state = RLE_STATE_SINGLE;
|
||||
rle_rdp = 0;
|
||||
rle_prev_v = 0;
|
||||
rle_cnt = 0;
|
||||
}
|
||||
|
||||
static uint8_t rle_next(void)
|
||||
{
|
||||
uint8_t v = 0;
|
||||
uint8_t ret = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
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.
|
||||
*
|
||||
* Compares the value of both input arguments.
|
||||
|
@ -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`*/
|
||||
|
@ -29,6 +29,7 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_FS_MAX_FN_LENGTH 64
|
||||
#define LV_FS_MAX_PATH_LENGTH 256
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
|
@ -26,7 +26,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,
|
||||
|
@ -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
|
||||
|
861
src/lv_misc/lv_printf.c
Normal file
861
src/lv_misc/lv_printf.c
Normal file
@ -0,0 +1,861 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// '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 <stddef.h> 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 <float.h>
|
||||
#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 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 <m.jasperse@gmail.com>
|
||||
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*/
|
||||
|
75
src/lv_misc/lv_printf.h
Normal file
75
src/lv_misc/lv_printf.h
Normal file
@ -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 <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* 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_
|
@ -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,45 @@ 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);
|
||||
/* 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;
|
||||
}
|
||||
/*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;
|
||||
}
|
||||
/*Always step at least one to avoid infinite loops*/
|
||||
if(i == 0) {
|
||||
lv_txt_encoded_next(txt, &i);
|
||||
}
|
||||
|
||||
return i;
|
||||
|
@ -14,11 +14,13 @@
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_anim.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_BAR_SIZE_MIN 4 /*hor. pad and ver. pad cannot make the indicator smaller then this [px]*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@ -30,6 +32,9 @@
|
||||
static lv_design_res_t lv_bar_design(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode);
|
||||
static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param);
|
||||
|
||||
static void draw_bg(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode, lv_opa_t opa);
|
||||
static void draw_indic(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode, lv_opa_t opa);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
static void lv_bar_anim(void * bar, lv_anim_value_t value);
|
||||
static void lv_bar_anim_ready(lv_anim_t * a);
|
||||
@ -359,112 +364,9 @@ static lv_design_res_t lv_bar_design(lv_obj_t * bar, const lv_area_t * clip_area
|
||||
} else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(bar);
|
||||
|
||||
#if LV_USE_GROUP == 0
|
||||
ancestor_design_f(bar, mask, mode);
|
||||
#else
|
||||
/* Draw the borders later if the bar is focused.
|
||||
* At value = 100% the indicator can cover to whole background and the focused style won't
|
||||
* be visible*/
|
||||
if(lv_obj_is_focused(bar)) {
|
||||
const lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, style_bg);
|
||||
style_tmp.body.border.width = 0;
|
||||
lv_draw_rect(&bar->coords, clip_area, &style_tmp, opa_scale);
|
||||
} else {
|
||||
ancestor_design_f(bar, clip_area, mode);
|
||||
}
|
||||
#endif
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
draw_bg(bar, clip_area, mode, opa_scale);
|
||||
draw_indic(bar, clip_area, mode, opa_scale);
|
||||
|
||||
if(ext->cur_value != ext->min_value || ext->sym
|
||||
#if LV_USE_ANIMATION
|
||||
|| ext->anim_start != LV_BAR_ANIM_STATE_INV
|
||||
#endif
|
||||
) {
|
||||
const lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
|
||||
lv_area_t indic_area;
|
||||
lv_area_copy(&indic_area, &bar->coords);
|
||||
indic_area.x1 += style_indic->body.padding.left;
|
||||
indic_area.x2 -= style_indic->body.padding.right;
|
||||
indic_area.y1 += style_indic->body.padding.top;
|
||||
indic_area.y2 -= style_indic->body.padding.bottom;
|
||||
|
||||
lv_coord_t w = lv_area_get_width(&indic_area);
|
||||
lv_coord_t h = lv_area_get_height(&indic_area);
|
||||
|
||||
if(w >= h) {
|
||||
/*Horizontal*/
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_x =
|
||||
(int32_t)((int32_t)w * (ext->anim_start - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
lv_coord_t anim_end_x =
|
||||
(int32_t)((int32_t)w * (ext->anim_end - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
indic_area.x2 =
|
||||
anim_start_x + (((anim_end_x - anim_start_x) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
indic_area.x2 =
|
||||
(int32_t)((int32_t)w * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
}
|
||||
|
||||
indic_area.x2 = indic_area.x1 + indic_area.x2 - 1;
|
||||
if(ext->sym && ext->min_value < 0 && ext->max_value > 0) {
|
||||
/*Calculate the coordinate of the zero point*/
|
||||
lv_coord_t zero;
|
||||
zero = indic_area.x1 + (-ext->min_value * w) / (ext->max_value - ext->min_value);
|
||||
if(indic_area.x2 > zero)
|
||||
indic_area.x1 = zero;
|
||||
else {
|
||||
indic_area.x1 = indic_area.x2;
|
||||
indic_area.x2 = zero;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_y =
|
||||
(int32_t)((int32_t)h * (ext->anim_start - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
lv_coord_t anim_end_y =
|
||||
(int32_t)((int32_t)h * (ext->anim_end - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
indic_area.y1 =
|
||||
anim_start_y + (((anim_end_y - anim_start_y) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
indic_area.y1 =
|
||||
(int32_t)((int32_t)h * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
}
|
||||
|
||||
indic_area.y1 = indic_area.y2 - indic_area.y1 + 1;
|
||||
|
||||
if(ext->sym && ext->min_value < 0 && ext->max_value > 0) {
|
||||
/*Calculate the coordinate of the zero point*/
|
||||
lv_coord_t zero;
|
||||
zero = indic_area.y2 - (-ext->min_value * h) / (ext->max_value - ext->min_value);
|
||||
if(indic_area.y1 < zero)
|
||||
indic_area.y2 = zero;
|
||||
else {
|
||||
indic_area.y2 = indic_area.y1;
|
||||
indic_area.y1 = zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Draw the indicator*/
|
||||
lv_draw_rect(&indic_area, clip_area, style_indic, opa_scale);
|
||||
}
|
||||
} else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
#if LV_USE_GROUP
|
||||
/*Draw the border*/
|
||||
if(lv_obj_is_focused(bar)) {
|
||||
@ -477,10 +379,151 @@ static lv_design_res_t lv_bar_design(lv_obj_t * bar, const lv_area_t * clip_area
|
||||
lv_draw_rect(&bar->coords, clip_area, &style_tmp, opa_scale);
|
||||
}
|
||||
#endif
|
||||
|
||||
} else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
|
||||
}
|
||||
return LV_DESIGN_RES_OK;
|
||||
}
|
||||
|
||||
static void draw_bg(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode, lv_opa_t opa)
|
||||
{
|
||||
|
||||
#if LV_USE_GROUP == 0
|
||||
/*Simply draw the background*/
|
||||
ancestor_design_f(bar, mask, mode);
|
||||
#else
|
||||
/* Draw the borders later if the bar is focused.
|
||||
* At value = 100% the indicator can cover to whole background and the focused style won't
|
||||
* be visible*/
|
||||
if(lv_obj_is_focused(bar)) {
|
||||
const lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, style_bg);
|
||||
style_tmp.body.border.width = 0;
|
||||
lv_draw_rect(&bar->coords, clip_area, &style_tmp, opa);
|
||||
} else {
|
||||
ancestor_design_f(bar, clip_area, mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_indic(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode, lv_opa_t opa)
|
||||
{
|
||||
(void) mode; /*Unused*/
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
|
||||
lv_coord_t objw = lv_obj_get_width(bar);
|
||||
lv_coord_t objh = lv_obj_get_height(bar);
|
||||
int32_t range = ext->max_value - ext->min_value;
|
||||
bool hor = objw >= objh ? true : false;
|
||||
bool sym = false;
|
||||
if(ext->sym && ext->min_value < 0 && ext->max_value > 0) sym = true;
|
||||
|
||||
bool anim = false;
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) anim = true;
|
||||
#endif
|
||||
|
||||
/*Calculate the indicator area*/
|
||||
lv_area_copy(&ext->indic_area, &bar->coords);
|
||||
const lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
|
||||
|
||||
/*Respect padding and minimum width/height too*/
|
||||
ext->indic_area.x1 += style_indic->body.padding.left;
|
||||
ext->indic_area.x2 -= style_indic->body.padding.right;
|
||||
ext->indic_area.y1 += style_indic->body.padding.top;
|
||||
ext->indic_area.y2 -= style_indic->body.padding.bottom;
|
||||
|
||||
if(hor && lv_area_get_height(&ext->indic_area) < LV_BAR_SIZE_MIN) {
|
||||
ext->indic_area.y1 = bar->coords.y1 + (objh / 2) - (LV_BAR_SIZE_MIN / 2);
|
||||
ext->indic_area.y2 = ext->indic_area.y1 + LV_BAR_SIZE_MIN;
|
||||
} else if(!hor && lv_area_get_width(&ext->indic_area) < LV_BAR_SIZE_MIN) {
|
||||
ext->indic_area.x1 = bar->coords.x1 + (objw / 2) - (LV_BAR_SIZE_MIN / 2);
|
||||
ext->indic_area.x2 = ext->indic_area.x1 + LV_BAR_SIZE_MIN;
|
||||
}
|
||||
|
||||
lv_coord_t indicw = lv_area_get_width(&ext->indic_area);
|
||||
lv_coord_t indich = lv_area_get_height(&ext->indic_area);
|
||||
|
||||
/*Calculate the indicator length*/
|
||||
lv_coord_t indic_length;
|
||||
if(anim) {
|
||||
#if LV_USE_ANIMATION
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_v = (int32_t)((int32_t)(hor ? indicw : indich) *
|
||||
(ext->anim_start - ext->min_value)) / range;
|
||||
lv_coord_t anim_end_v = (int32_t)((int32_t)(hor ? indicw : indich) *
|
||||
(ext->anim_end - ext->min_value)) / range;
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
indic_length = anim_start_v + (((anim_end_v - anim_start_v) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
indic_length = (int32_t)((int32_t)(hor ? indicw : indich) * (ext->cur_value - ext->min_value)) /
|
||||
(ext->max_value - ext->min_value);
|
||||
}
|
||||
|
||||
/*Horizontal bar*/
|
||||
if(hor) {
|
||||
ext->indic_area.x2 = ext->indic_area.x1 + indic_length - 1;
|
||||
if(sym) {
|
||||
lv_coord_t zero;
|
||||
zero = ext->indic_area.x1 + (-ext->min_value * indicw) / range;
|
||||
if(ext->indic_area.x2 > zero)
|
||||
ext->indic_area.x1 = zero;
|
||||
else {
|
||||
ext->indic_area.x1 = ext->indic_area.x2;
|
||||
ext->indic_area.x2 = zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Vertical bar*/
|
||||
else {
|
||||
ext->indic_area.y1 = ext->indic_area.y2 - indic_length + 1;
|
||||
if(sym) {
|
||||
lv_coord_t zero;
|
||||
zero = ext->indic_area.y2 - (-ext->min_value * objh) / range;
|
||||
if(ext->indic_area.y1 < zero)
|
||||
ext->indic_area.y2 = zero;
|
||||
else {
|
||||
ext->indic_area.y2 = ext->indic_area.y1;
|
||||
ext->indic_area.y1 = zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Draw the indicator*/
|
||||
|
||||
/*Do not draw a zero length indicator*/
|
||||
if(!sym && indic_length == 0) return;
|
||||
|
||||
lv_area_t mask_area;
|
||||
lv_area_copy(&mask_area, &bar->coords);
|
||||
mask_area.x1 -= style_indic->body.shadow.width;
|
||||
mask_area.y1 -= style_indic->body.shadow.width;
|
||||
mask_area.x2 += style_indic->body.shadow.width;
|
||||
mask_area.y2 += style_indic->body.shadow.width;
|
||||
|
||||
if(style_indic->body.shadow.offset.x > 0) mask_area.x1 += style_indic->body.shadow.offset.x;
|
||||
else mask_area.x2 -= style_indic->body.shadow.offset.x;
|
||||
|
||||
if(style_indic->body.shadow.offset.y > 0) mask_area.y1 += style_indic->body.shadow.offset.y;
|
||||
else mask_area.y2 -= style_indic->body.shadow.offset.y;
|
||||
|
||||
lv_draw_mask_param_t mask_param;
|
||||
lv_draw_mask_radius_init(&mask_param, &mask_area,style_indic->body.radius, false);
|
||||
int16_t bg_mask_id = lv_draw_mask_add(&mask_param, NULL);
|
||||
|
||||
lv_draw_rect(&ext->indic_area, clip_area, style_indic, opa);
|
||||
|
||||
lv_draw_mask_remove_id(bg_mask_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the bar
|
||||
* @param bar pointer to a bar object
|
||||
@ -498,6 +541,17 @@ static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param)
|
||||
|
||||
if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
|
||||
const lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
|
||||
const lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);
|
||||
|
||||
lv_coord_t bg_size = style_bg->body.shadow.width + style_bg->body.shadow.spread;
|
||||
bg_size += LV_MATH_MAX(LV_MATH_ABS(style_bg->body.shadow.offset.x), LV_MATH_ABS(style_bg->body.shadow.offset.y));
|
||||
|
||||
lv_coord_t indic_size = style_indic->body.shadow.width + style_indic->body.shadow.spread;
|
||||
indic_size += LV_MATH_MAX(LV_MATH_ABS(style_indic->body.shadow.offset.x), LV_MATH_ABS(style_indic->body.shadow.offset.y));
|
||||
|
||||
bar->ext_draw_pad = LV_MATH_MAX(bar->ext_draw_pad, bg_size);
|
||||
bar->ext_draw_pad = LV_MATH_MAX(bar->ext_draw_pad, indic_size);
|
||||
|
||||
if(style_indic->body.shadow.width > bar->ext_draw_pad) bar->ext_draw_pad = style_indic->body.shadow.width;
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
|
@ -56,6 +56,7 @@ typedef struct
|
||||
int16_t cur_value; /*Current value of the bar*/
|
||||
int16_t min_value; /*Minimum value of the bar*/
|
||||
int16_t max_value; /*Maximum value of the bar*/
|
||||
lv_area_t indic_area; /*Save the indicator area. MIght be used by derived types*/
|
||||
#if LV_USE_ANIMATION
|
||||
lv_anim_value_t anim_start;
|
||||
lv_anim_value_t anim_end;
|
||||
|
@ -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*/
|
||||
@ -862,7 +862,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;
|
||||
}
|
||||
}
|
||||
@ -883,7 +883,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;
|
||||
}
|
||||
|
@ -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"*/
|
||||
|
@ -505,6 +505,8 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
|
||||
|
||||
set_set_px_cb(&disp.driver, dsc->header.cf);
|
||||
|
||||
#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 &&
|
||||
@ -513,6 +515,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);
|
||||
@ -671,6 +674,7 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t * points, uint32_t
|
||||
|
||||
set_set_px_cb(&disp.driver, dsc->header.cf);
|
||||
|
||||
#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 &&
|
||||
@ -679,6 +683,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);
|
||||
@ -725,6 +730,7 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t * points, uint32
|
||||
|
||||
set_set_px_cb(&disp.driver, dsc->header.cf);
|
||||
|
||||
#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 &&
|
||||
@ -733,6 +739,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);
|
||||
@ -780,6 +787,7 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_
|
||||
|
||||
set_set_px_cb(&disp.driver, dsc->header.cf);
|
||||
|
||||
#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 &&
|
||||
@ -788,6 +796,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);
|
||||
|
@ -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*/
|
||||
|
||||
|
@ -620,11 +620,20 @@ static lv_design_res_t lv_chart_design(lv_obj_t * chart, const lv_area_t * clip_
|
||||
|
||||
lv_chart_draw_div(chart, clip_area);
|
||||
|
||||
if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, clip_area);
|
||||
if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, clip_area);
|
||||
if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, clip_area);
|
||||
if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, clip_area);
|
||||
if((ext->type & LV_CHART_TYPE_AREA) || (ext->type & LV_CHART_TYPE_AREA_FADED)) lv_chart_draw_areas(chart, clip_area);
|
||||
/* 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, clip_area, &mask_tmp);
|
||||
|
||||
if(union_ok) {
|
||||
if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, clip_area);
|
||||
if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, clip_area);
|
||||
if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, clip_area);
|
||||
if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, clip_area);
|
||||
if((ext->type & LV_CHART_TYPE_AREA) || (ext->type & LV_CHART_TYPE_AREA_FADED)) lv_chart_draw_areas(chart, clip_area);
|
||||
}
|
||||
|
||||
lv_chart_draw_axes(chart, clip_area);
|
||||
}
|
||||
|
@ -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");
|
||||
@ -230,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 {
|
||||
@ -237,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);
|
||||
}
|
||||
|
||||
@ -571,9 +580,14 @@ static lv_design_res_t lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * cli
|
||||
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;
|
||||
@ -773,13 +787,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;
|
||||
|
@ -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);
|
||||
|
@ -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+1, 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.
|
||||
@ -585,14 +631,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 +651,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ extern "C" {
|
||||
|
||||
#if LV_USE_LABEL != 0
|
||||
|
||||
#include <stdarg.h>
|
||||
#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.
|
||||
|
@ -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);
|
||||
@ -366,6 +363,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_layout_t layout)
|
||||
{
|
||||
/* Update list layout if necessary */
|
||||
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 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);
|
||||
}
|
||||
|
||||
btn = lv_list_get_prev_btn(list, btn);
|
||||
}
|
||||
|
||||
lv_page_set_scrl_layout(list, layout);
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
@ -529,15 +556,24 @@ 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_layout_t lv_list_get_layout(lv_obj_t * list)
|
||||
{
|
||||
return lv_page_get_scrl_layout(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +594,7 @@ const lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
@ -751,10 +788,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 +809,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 +900,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);
|
||||
|
@ -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;
|
||||
|
||||
@ -189,6 +192,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_layout_t layout);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
@ -259,6 +269,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 of the list object
|
||||
*/
|
||||
lv_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
|
||||
|
@ -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 = 0;
|
||||
}
|
||||
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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -498,7 +506,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;
|
||||
|
@ -18,8 +18,6 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_SLIDER_SIZE_MIN 4 /*hor. pad and ver. pad cannot make the bar or indicator smaller then this [px]*/
|
||||
#define LV_SLIDER_NOT_PRESSED INT16_MIN
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@ -69,9 +67,7 @@ lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
/*Initialize the allocated 'ext' */
|
||||
ext->drag_value = LV_SLIDER_NOT_PRESSED;
|
||||
ext->style_knob = &lv_style_pretty;
|
||||
ext->knob_in = 0;
|
||||
|
||||
/*The signal and design functions are not copied so set them here*/
|
||||
lv_obj_set_signal_cb(new_slider, lv_slider_signal);
|
||||
@ -96,7 +92,6 @@ lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
else {
|
||||
lv_slider_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
|
||||
ext->style_knob = copy_ext->style_knob;
|
||||
ext->knob_in = copy_ext->knob_in;
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_slider);
|
||||
}
|
||||
@ -110,21 +105,6 @@ lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set the 'knob in' attribute of a slider
|
||||
* @param slider pointer to slider object
|
||||
* @param in true: the knob is drawn always in the slider;
|
||||
* false: the knob can be out on the edges
|
||||
*/
|
||||
void lv_slider_set_knob_in(lv_obj_t * slider, bool in)
|
||||
{
|
||||
lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);
|
||||
if(ext->knob_in == in) return;
|
||||
|
||||
ext->knob_in = in == false ? 0 : 1;
|
||||
lv_obj_invalidate(slider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a style of a slider
|
||||
* @param slider pointer to a slider object
|
||||
@ -156,12 +136,7 @@ void lv_slider_set_style(lv_obj_t * slider, lv_slider_style_t type, const lv_sty
|
||||
*/
|
||||
int16_t lv_slider_get_value(const lv_obj_t * slider)
|
||||
{
|
||||
lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);
|
||||
|
||||
if(ext->drag_value != LV_SLIDER_NOT_PRESSED)
|
||||
return ext->drag_value;
|
||||
else
|
||||
return lv_bar_get_value(slider);
|
||||
return lv_bar_get_value(slider);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,19 +147,7 @@ int16_t lv_slider_get_value(const lv_obj_t * slider)
|
||||
bool lv_slider_is_dragged(const lv_obj_t * slider)
|
||||
{
|
||||
lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);
|
||||
return ext->drag_value == LV_SLIDER_NOT_PRESSED ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'knob in' attribute of a slider
|
||||
* @param slider pointer to slider object
|
||||
* @return true: the knob is drawn always in the slider;
|
||||
* false: the knob can be out on the edges
|
||||
*/
|
||||
bool lv_slider_get_knob_in(const lv_obj_t * slider)
|
||||
{
|
||||
lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);
|
||||
return ext->knob_in == 0 ? false : true;
|
||||
return ext->dragging ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,218 +193,63 @@ static lv_design_res_t lv_slider_design(lv_obj_t * slider, const lv_area_t * cli
|
||||
}
|
||||
/*Draw the object*/
|
||||
else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
|
||||
/*The ancestor design function will draw the background and the indicator.
|
||||
* It also sets ext->bar.indic_area*/
|
||||
ancestor_design_f(slider, clip_area, mode);
|
||||
|
||||
lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);
|
||||
|
||||
const lv_style_t * style_bg = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG);
|
||||
const lv_style_t * style_knob = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB);
|
||||
const lv_style_t * style_indic = lv_slider_get_style(slider, LV_SLIDER_STYLE_INDIC);
|
||||
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(slider);
|
||||
|
||||
lv_coord_t slider_w = lv_area_get_width(&slider->coords);
|
||||
lv_coord_t slider_h = lv_area_get_height(&slider->coords);
|
||||
lv_coord_t objw = lv_obj_get_width(slider);
|
||||
lv_coord_t objh = lv_obj_get_height(slider);
|
||||
bool hor = objw >= objh ? true : false;
|
||||
lv_coord_t knob_size = hor ? objh : objw;
|
||||
bool sym = false;
|
||||
if(ext->bar.sym && ext->bar.min_value < 0 && ext->bar.max_value > 0) sym = true;
|
||||
|
||||
/*Draw the bar*/
|
||||
lv_area_t area_bg;
|
||||
lv_area_copy(&area_bg, &slider->coords);
|
||||
|
||||
/*Be sure at least LV_SLIDER_SIZE_MIN size will remain*/
|
||||
lv_coord_t pad_top_bg = style_bg->body.padding.top;
|
||||
lv_coord_t pad_bottom_bg = style_bg->body.padding.bottom;
|
||||
lv_coord_t pad_left_bg = style_bg->body.padding.left;
|
||||
lv_coord_t pad_right_bg = style_bg->body.padding.right;
|
||||
if(pad_top_bg + pad_bottom_bg + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) {
|
||||
pad_top_bg = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;
|
||||
pad_bottom_bg = pad_top_bg;
|
||||
}
|
||||
if(pad_left_bg + pad_right_bg + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) {
|
||||
pad_left_bg = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;
|
||||
pad_right_bg = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;
|
||||
}
|
||||
|
||||
if(ext->knob_in) { /*Enable extra size if the knob is inside */
|
||||
area_bg.x1 += pad_left_bg;
|
||||
area_bg.x2 -= pad_right_bg;
|
||||
area_bg.y1 += pad_top_bg;
|
||||
area_bg.y2 -= pad_bottom_bg;
|
||||
} else { /*Let space only in the perpendicular directions*/
|
||||
area_bg.x1 += slider_w < slider_h ? pad_left_bg : 0; /*Pad only for vertical slider*/
|
||||
area_bg.x2 -= slider_w < slider_h ? pad_right_bg : 0; /*Pad only for vertical slider*/
|
||||
area_bg.y1 += slider_w > slider_h ? pad_top_bg : 0; /*Pad only for horizontal slider*/
|
||||
area_bg.y2 -= slider_w > slider_h ? pad_bottom_bg : 0; /*Pad only for horizontal slider*/
|
||||
}
|
||||
|
||||
#if LV_USE_GROUP == 0
|
||||
lv_draw_rect(&area_bg, clip_area, style_bg, lv_obj_get_opa_scale(slider));
|
||||
#else
|
||||
/* Draw the borders later if the slider is focused.
|
||||
* At value = 100% the indicator can cover to whole background and the focused style won't
|
||||
* be visible*/
|
||||
if(lv_obj_is_focused(slider)) {
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, style_bg);
|
||||
style_tmp.body.border.width = 0;
|
||||
lv_draw_rect(&area_bg, clip_area, &style_tmp, opa_scale);
|
||||
} else {
|
||||
lv_draw_rect(&area_bg, clip_area, style_bg, opa_scale);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Draw the indicator*/
|
||||
lv_area_t area_indic;
|
||||
lv_area_copy(&area_indic, &area_bg);
|
||||
|
||||
/*Be sure at least ver pad/hor pad width indicator will remain*/
|
||||
lv_coord_t pad_top_indic = style_indic->body.padding.top;
|
||||
lv_coord_t pad_bottom_indic = style_indic->body.padding.bottom;
|
||||
lv_coord_t pad_left_indic = style_indic->body.padding.left;
|
||||
lv_coord_t pad_right_indic = style_indic->body.padding.right;
|
||||
if(pad_top_indic + pad_bottom_indic + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) {
|
||||
pad_top_indic = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;
|
||||
pad_bottom_indic = pad_top_indic;
|
||||
}
|
||||
if(pad_left_indic + pad_right_indic + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) {
|
||||
pad_left_indic = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;
|
||||
pad_right_indic = pad_left_indic;
|
||||
}
|
||||
|
||||
area_indic.x1 += pad_left_indic;
|
||||
area_indic.x2 -= pad_right_indic;
|
||||
area_indic.y1 += pad_top_indic;
|
||||
area_indic.y2 -= pad_bottom_indic;
|
||||
|
||||
lv_coord_t cur_value = lv_slider_get_value(slider);
|
||||
lv_coord_t min_value = lv_slider_get_min_value(slider);
|
||||
lv_coord_t max_value = lv_slider_get_max_value(slider);
|
||||
|
||||
/*If dragged draw to the drag position*/
|
||||
if(ext->drag_value != LV_SLIDER_NOT_PRESSED) cur_value = ext->drag_value;
|
||||
|
||||
if(slider_w >= slider_h) {
|
||||
lv_coord_t indic_w = lv_area_get_width(&area_indic);
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_x =
|
||||
(int32_t)((int32_t)indic_w * (ext->bar.anim_start - min_value)) / (max_value - min_value);
|
||||
lv_coord_t anim_end_x =
|
||||
(int32_t)((int32_t)indic_w * (ext->bar.anim_end - min_value)) / (max_value - min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
area_indic.x2 = anim_start_x + (((anim_end_x - anim_start_x) * ext->bar.anim_state) >> 8);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
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;
|
||||
|
||||
/*Draw the indicator but don't draw an ugly 1px wide rectangle on the left on min.
|
||||
* value*/
|
||||
if(area_indic.x1 != area_indic.x2) lv_draw_rect(&area_indic, clip_area, style_indic, opa_scale);
|
||||
|
||||
} else {
|
||||
lv_coord_t indic_h = lv_area_get_height(&area_indic);
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_y =
|
||||
(int32_t)((int32_t)indic_h * (ext->bar.anim_start - min_value)) / (max_value - min_value);
|
||||
lv_coord_t anim_end_y =
|
||||
(int32_t)((int32_t)indic_h * (ext->bar.anim_end - min_value)) / (max_value - min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
area_indic.y1 = anim_start_y + (((anim_end_y - anim_start_y) * ext->bar.anim_state) >> 8);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
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;
|
||||
|
||||
/*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, clip_area, style_indic, opa_scale);
|
||||
}
|
||||
|
||||
/*Before the knob add the border if required*/
|
||||
#if LV_USE_GROUP
|
||||
/* Draw the borders later if the bar is focused.
|
||||
* At value = 100% the indicator can cover to whole background and the focused style won't
|
||||
* be visible*/
|
||||
if(lv_obj_is_focused(slider)) {
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, style_bg);
|
||||
style_tmp.body.opa = LV_OPA_TRANSP;
|
||||
style_tmp.body.shadow.width = 0;
|
||||
lv_draw_rect(&area_bg, clip_area, &style_tmp, opa_scale);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Draw the knob*/
|
||||
lv_area_t knob_area;
|
||||
lv_area_copy(&knob_area, &slider->coords);
|
||||
|
||||
if(slider_w >= slider_h) {
|
||||
if(ext->knob_in == 0) {
|
||||
knob_area.x1 = area_indic.x2 - slider_h / 2;
|
||||
knob_area.x2 = knob_area.x1 + slider_h - 1;
|
||||
/*Horizontal*/
|
||||
if(hor) {
|
||||
if(!sym) {
|
||||
knob_area.x1 = ext->bar.indic_area.x2;
|
||||
} else {
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
lv_coord_t w = slider_w - slider_h - 1;
|
||||
lv_coord_t anim_start_x =
|
||||
(int32_t)((int32_t)w * (ext->bar.anim_start - min_value)) / (max_value - min_value);
|
||||
lv_coord_t anim_end_x =
|
||||
(int32_t)((int32_t)w * (ext->bar.anim_end - min_value)) / (max_value - min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
knob_area.x1 = anim_start_x + (((anim_end_x - anim_start_x) * ext->bar.anim_state) >> 8);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
knob_area.x1 = (int32_t)((int32_t)(slider_w - slider_h - 1) * (cur_value - min_value)) /
|
||||
(max_value - min_value);
|
||||
if(ext->bar.cur_value >= 0) {
|
||||
knob_area.x1 = ext->bar.indic_area.x2;
|
||||
} else {
|
||||
knob_area.x1 = ext->bar.indic_area.x1;
|
||||
}
|
||||
|
||||
knob_area.x1 += slider->coords.x1;
|
||||
knob_area.x2 = knob_area.x1 + slider_h - 1;
|
||||
}
|
||||
|
||||
knob_area.x1 -= (knob_size >> 1);
|
||||
knob_area.x2 = knob_area.x1 + knob_size;
|
||||
knob_area.y1 = slider->coords.y1;
|
||||
knob_area.y2 = slider->coords.y2;
|
||||
} else {
|
||||
if(ext->knob_in == 0) {
|
||||
knob_area.y1 = area_indic.y1 - slider_w / 2;
|
||||
knob_area.y2 = knob_area.y1 + slider_w - 1;
|
||||
} else {
|
||||
#if LV_USE_ANIMATION
|
||||
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
lv_coord_t h = slider_h - slider_w - 1;
|
||||
lv_coord_t anim_start_x =
|
||||
(int32_t)((int32_t)h * (ext->bar.anim_start - min_value)) / (max_value - min_value);
|
||||
lv_coord_t anim_end_x =
|
||||
(int32_t)((int32_t)h * (ext->bar.anim_end - min_value)) / (max_value - min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and
|
||||
* `anim_end`)*/
|
||||
knob_area.y2 = anim_start_x + (((anim_end_x - anim_start_x) * ext->bar.anim_state) >> 8);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
knob_area.y2 = (int32_t)((int32_t)(slider_h - slider_w - 1) * (cur_value - min_value)) /
|
||||
(max_value - min_value);
|
||||
}
|
||||
|
||||
knob_area.y2 = slider->coords.y2 - knob_area.y2;
|
||||
knob_area.y1 = knob_area.y2 - slider_w - 1;
|
||||
}
|
||||
knob_area.x1 = slider->coords.x1;
|
||||
knob_area.x2 = slider->coords.x2;
|
||||
}
|
||||
/*Vertical*/
|
||||
else {
|
||||
if(!sym) {
|
||||
knob_area.y1 = ext->bar.indic_area.y1;
|
||||
} else {
|
||||
if(ext->bar.cur_value >= 0) {
|
||||
knob_area.y1 = ext->bar.indic_area.y1;
|
||||
} else {
|
||||
knob_area.y1 = ext->bar.indic_area.y2;
|
||||
}
|
||||
}
|
||||
knob_area.y1 -= (knob_size >> 1);
|
||||
knob_area.y2 = knob_area.y1 + knob_size;
|
||||
knob_area.x1 = slider->coords.x1;
|
||||
knob_area.x2 = slider->coords.x2;
|
||||
}
|
||||
|
||||
/*Apply the paddings on the knob area*/
|
||||
knob_area.x1 -= style_knob->body.padding.left;
|
||||
knob_area.x2 += style_knob->body.padding.right;
|
||||
knob_area.y1 -= style_knob->body.padding.top;
|
||||
knob_area.y2 += style_knob->body.padding.bottom;
|
||||
|
||||
lv_draw_rect(&knob_area, clip_area, style_knob, opa_scale);
|
||||
}
|
||||
/*Post draw when the children are drawn*/
|
||||
@ -468,42 +276,42 @@ static lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * par
|
||||
|
||||
lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);
|
||||
lv_point_t p;
|
||||
lv_coord_t w = lv_obj_get_width(slider);
|
||||
lv_coord_t h = lv_obj_get_height(slider);
|
||||
|
||||
if(sign == LV_SIGNAL_PRESSED) {
|
||||
ext->drag_value = lv_slider_get_value(slider);
|
||||
ext->dragging = true;
|
||||
} else if(sign == LV_SIGNAL_PRESSING) {
|
||||
lv_indev_get_point(param, &p);
|
||||
int16_t tmp = 0;
|
||||
if(w > h) {
|
||||
lv_coord_t knob_w = h;
|
||||
p.x -=
|
||||
slider->coords.x1 + h / 2; /*Modify the point to shift with half knob (important on the start and end)*/
|
||||
tmp = (int32_t)((int32_t)p.x * (ext->bar.max_value - ext->bar.min_value + 1)) / (w - knob_w);
|
||||
tmp += ext->bar.min_value;
|
||||
|
||||
lv_coord_t w = lv_obj_get_width(slider);
|
||||
lv_coord_t h = lv_obj_get_height(slider);
|
||||
const lv_style_t * indic_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_INDIC);
|
||||
int32_t range = ext->bar.max_value - ext->bar.min_value;
|
||||
int16_t new_value = 0;
|
||||
if(w >= h) {
|
||||
lv_coord_t indic_w = w - indic_style->body.padding.left - indic_style->body.padding.right;
|
||||
int32_t range = ext->bar.max_value - ext->bar.min_value;
|
||||
new_value = p.x - (slider->coords.x1 + indic_style->body.padding.left); /*Make the point relative to the indicator*/
|
||||
new_value = (new_value * range) / indic_w;
|
||||
new_value += ext->bar.min_value;
|
||||
} else {
|
||||
lv_coord_t knob_h = w;
|
||||
p.y -=
|
||||
slider->coords.y1 + w / 2; /*Modify the point to shift with half knob (important on the start and end)*/
|
||||
tmp = (int32_t)((int32_t)p.y * (ext->bar.max_value - ext->bar.min_value + 1)) / (h - knob_h);
|
||||
tmp = ext->bar.max_value - tmp; /*Invert the value: smaller value means higher y*/
|
||||
lv_coord_t indic_h = h - indic_style->body.padding.bottom - indic_style->body.padding.top;
|
||||
new_value = p.y - (slider->coords.y2 + indic_style->body.padding.bottom); /*Make the point relative to the indicator*/
|
||||
new_value = (-new_value * range) / indic_h;
|
||||
new_value += ext->bar.min_value;
|
||||
|
||||
}
|
||||
|
||||
if(tmp < ext->bar.min_value)
|
||||
tmp = ext->bar.min_value;
|
||||
else if(tmp > ext->bar.max_value)
|
||||
tmp = ext->bar.max_value;
|
||||
if(new_value < ext->bar.min_value) new_value = ext->bar.min_value;
|
||||
else if(new_value > ext->bar.max_value) new_value = ext->bar.max_value;
|
||||
|
||||
if(tmp != ext->drag_value) {
|
||||
ext->drag_value = tmp;
|
||||
if(new_value != ext->bar.cur_value) {
|
||||
ext->bar.cur_value = new_value;
|
||||
lv_obj_invalidate(slider);
|
||||
res = lv_event_send(slider, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
if(res != LV_RES_OK) return res;
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) {
|
||||
if(ext->drag_value != LV_SLIDER_NOT_PRESSED) lv_slider_set_value(slider, ext->drag_value, false);
|
||||
ext->drag_value = LV_SLIDER_NOT_PRESSED;
|
||||
ext->dragging = false;
|
||||
|
||||
#if LV_USE_GROUP
|
||||
/*Leave edit mode if released. (No need to wait for LONG_PRESS) */
|
||||
@ -523,30 +331,32 @@ static lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * par
|
||||
slider->signal_cb(slider, LV_SIGNAL_REFR_EXT_DRAW_PAD, NULL);
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
|
||||
const lv_style_t * style = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG);
|
||||
const lv_style_t * bg_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG);
|
||||
const lv_style_t * indic_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_INDIC);
|
||||
const lv_style_t * knob_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB);
|
||||
|
||||
lv_coord_t shadow_w = knob_style->body.shadow.width;
|
||||
if(ext->knob_in == 0) {
|
||||
/* The smaller size is the knob diameter*/
|
||||
lv_coord_t x = LV_MATH_MIN(w / 2 + 1 + shadow_w, h / 2 + 1 + shadow_w);
|
||||
if(slider->ext_draw_pad < x) slider->ext_draw_pad = x;
|
||||
} else {
|
||||
lv_coord_t pad = 0;
|
||||
pad = LV_MATH_MIN(pad, style->body.padding.top);
|
||||
pad = LV_MATH_MIN(pad, style->body.padding.bottom);
|
||||
pad = LV_MATH_MIN(pad, style->body.padding.left);
|
||||
pad = LV_MATH_MIN(pad, style->body.padding.right);
|
||||
if(pad < 0) pad = -pad;
|
||||
if(slider->ext_draw_pad < pad) slider->ext_draw_pad = pad;
|
||||
/* The smaller size is the knob diameter*/
|
||||
lv_coord_t knob_size = LV_MATH_MIN(lv_obj_get_width(slider), lv_obj_get_height(slider)) >> 1;
|
||||
knob_size += LV_MATH_MAX(
|
||||
LV_MATH_MAX(knob_style->body.padding.left, knob_style->body.padding.right),
|
||||
LV_MATH_MAX(knob_style->body.padding.bottom,knob_style->body.padding.top));
|
||||
|
||||
knob_size += knob_style->body.shadow.width + knob_style->body.shadow.spread;
|
||||
knob_size += LV_MATH_MAX(LV_MATH_ABS(knob_style->body.shadow.offset.x), LV_MATH_ABS(knob_style->body.shadow.offset.y));
|
||||
|
||||
lv_coord_t bg_size = bg_style->body.shadow.width + bg_style->body.shadow.spread;
|
||||
bg_size += LV_MATH_MAX(LV_MATH_ABS(bg_style->body.shadow.offset.x), LV_MATH_ABS(bg_style->body.shadow.offset.y));
|
||||
|
||||
lv_coord_t indic_size = indic_style->body.shadow.width + indic_style->body.shadow.spread;
|
||||
indic_size += LV_MATH_MAX(LV_MATH_ABS(indic_style->body.shadow.offset.x), LV_MATH_ABS(indic_style->body.shadow.offset.y));
|
||||
|
||||
slider->ext_draw_pad = LV_MATH_MAX(slider->ext_draw_pad, knob_size);
|
||||
slider->ext_draw_pad = LV_MATH_MAX(slider->ext_draw_pad, indic_size);
|
||||
slider->ext_draw_pad = LV_MATH_MAX(slider->ext_draw_pad, bg_size);
|
||||
|
||||
if(slider->ext_draw_pad < shadow_w) slider->ext_draw_pad = shadow_w;
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_CONTROL) {
|
||||
char c = *((char *)param);
|
||||
|
||||
ext->drag_value = LV_SLIDER_NOT_PRESSED;
|
||||
|
||||
if(c == LV_KEY_RIGHT || c == LV_KEY_UP) {
|
||||
lv_slider_set_value(slider, lv_slider_get_value(slider) + 1, true);
|
||||
res = lv_event_send(slider, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
@ -42,8 +42,7 @@ typedef struct
|
||||
lv_bar_ext_t bar; /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
const lv_style_t * style_knob; /*Style of the knob*/
|
||||
int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/
|
||||
uint8_t knob_in : 1; /*1: Draw the knob inside the bar*/
|
||||
uint8_t dragging :1; /*1: the slider is being dragged*/
|
||||
} lv_slider_ext_t;
|
||||
|
||||
/** Built-in styles of slider*/
|
||||
@ -93,9 +92,10 @@ 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)
|
||||
{
|
||||
@ -103,12 +103,14 @@ static inline void lv_slider_set_anim_time(lv_obj_t * slider, uint16_t anim_time
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'knob in' attribute of a slider
|
||||
* @param slider pointer to slider object
|
||||
* @param in true: the knob is drawn always in the slider;
|
||||
* false: the knob can be out on the edges
|
||||
* Set the animation time of the slider
|
||||
* @param slider pointer to a bar object
|
||||
* @param anim_time the animation time in milliseconds.
|
||||
*/
|
||||
void lv_slider_set_knob_in(lv_obj_t * slider, bool in);
|
||||
static inline void lv_slider_set_sym(lv_obj_t * slider, bool en)
|
||||
{
|
||||
lv_bar_set_sym(slider, en);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a style of a slider
|
||||
@ -157,12 +159,24 @@ 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 'knob in' attribute of a slider
|
||||
* @param slider pointer to slider object
|
||||
* @return true: the knob is drawn always in the slider;
|
||||
* false: the knob can be out on the edges
|
||||
* Get the animation time of the slider
|
||||
* @param slider pointer to a slider object
|
||||
* @return the animation time in milliseconds.
|
||||
*/
|
||||
bool lv_slider_get_knob_in(const lv_obj_t * slider);
|
||||
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 a style of a slider
|
||||
|
@ -29,12 +29,14 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_design_res_t lv_sw_design(lv_obj_t * slider, const lv_area_t * clip_area, lv_design_mode_t mode);
|
||||
static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_signal_cb_t ancestor_signal;
|
||||
static lv_design_cb_t ancestor_design;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -55,11 +57,12 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
LV_LOG_TRACE("switch create started");
|
||||
|
||||
/*Create the ancestor of switch*/
|
||||
lv_obj_t * new_sw = lv_slider_create(par, copy);
|
||||
lv_obj_t * new_sw = lv_bar_create(par, copy);
|
||||
lv_mem_assert(new_sw);
|
||||
if(new_sw == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_sw);
|
||||
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(new_sw);
|
||||
|
||||
/*Allocate the switch type specific extended data*/
|
||||
lv_sw_ext_t * ext = lv_obj_allocate_ext_attr(new_sw, sizeof(lv_sw_ext_t));
|
||||
@ -71,17 +74,19 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
#if LV_USE_ANIMATION
|
||||
ext->anim_time = 0;
|
||||
#endif
|
||||
ext->style_knob_off = ext->slider.style_knob;
|
||||
ext->style_knob_on = ext->slider.style_knob;
|
||||
ext->style_knob_off = &lv_style_pretty;
|
||||
ext->style_knob_on = &lv_style_pretty;
|
||||
|
||||
/*The signal and design functions are not copied so set them here*/
|
||||
lv_obj_set_signal_cb(new_sw, lv_sw_signal);
|
||||
lv_obj_set_design_cb(new_sw, lv_sw_design);
|
||||
|
||||
/*Init the new switch switch*/
|
||||
if(copy == NULL) {
|
||||
lv_obj_set_click(new_sw, true);
|
||||
lv_obj_set_protect(new_sw, LV_PROTECT_PRESS_LOST);
|
||||
lv_obj_set_size(new_sw, 2 * LV_DPI / 3, LV_DPI / 3);
|
||||
lv_slider_set_knob_in(new_sw, true);
|
||||
lv_slider_set_range(new_sw, 0, LV_SW_MAX_VALUE);
|
||||
lv_bar_set_range(new_sw, 0, LV_SW_MAX_VALUE);
|
||||
|
||||
/*Set the default styles*/
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
@ -93,7 +98,6 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
} else {
|
||||
/*Let the slider' style*/
|
||||
}
|
||||
|
||||
}
|
||||
/*Copy an existing switch*/
|
||||
else {
|
||||
@ -104,11 +108,6 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
ext->anim_time = copy_ext->anim_time;
|
||||
#endif
|
||||
|
||||
if(lv_sw_get_state(new_sw))
|
||||
lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);
|
||||
else
|
||||
lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);
|
||||
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_sw);
|
||||
}
|
||||
@ -133,8 +132,9 @@ void lv_sw_on(lv_obj_t * sw, lv_anim_enable_t anim)
|
||||
anim = LV_ANIM_OFF;
|
||||
#endif
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
lv_slider_set_value(sw, LV_SW_MAX_VALUE, anim);
|
||||
lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);
|
||||
ext->state = 1;
|
||||
lv_bar_set_value(sw, LV_SW_MAX_VALUE, anim);
|
||||
lv_obj_invalidate(sw);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,8 +148,9 @@ void lv_sw_off(lv_obj_t * sw, lv_anim_enable_t anim)
|
||||
anim = LV_ANIM_OFF;
|
||||
#endif
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
lv_slider_set_value(sw, 0, anim);
|
||||
lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);
|
||||
ext->state = 0;
|
||||
lv_bar_set_value(sw, 0, anim);
|
||||
lv_obj_invalidate(sw);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,15 +185,15 @@ void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, const lv_style_t * style
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
|
||||
switch(type) {
|
||||
case LV_SLIDER_STYLE_BG: lv_slider_set_style(sw, LV_SLIDER_STYLE_BG, style); break;
|
||||
case LV_SLIDER_STYLE_INDIC: lv_bar_set_style(sw, LV_SLIDER_STYLE_INDIC, style); break;
|
||||
case LV_SW_STYLE_BG: lv_bar_set_style(sw, LV_BAR_STYLE_BG, style); break;
|
||||
case LV_SW_STYLE_INDIC: lv_bar_set_style(sw, LV_BAR_STYLE_INDIC, style); break;
|
||||
case LV_SW_STYLE_KNOB_OFF:
|
||||
ext->style_knob_off = style;
|
||||
if(lv_sw_get_state(sw) == 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style);
|
||||
lv_obj_invalidate(sw);
|
||||
break;
|
||||
case LV_SW_STYLE_KNOB_ON:
|
||||
ext->style_knob_on = style;
|
||||
if(lv_sw_get_state(sw) != 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style);
|
||||
lv_obj_invalidate(sw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -224,8 +225,8 @@ const lv_style_t * lv_sw_get_style(const lv_obj_t * sw, lv_sw_style_t type)
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
|
||||
switch(type) {
|
||||
case LV_SW_STYLE_BG: style = lv_slider_get_style(sw, LV_SLIDER_STYLE_BG); break;
|
||||
case LV_SW_STYLE_INDIC: style = lv_slider_get_style(sw, LV_SLIDER_STYLE_INDIC); break;
|
||||
case LV_SW_STYLE_BG: style = lv_bar_get_style(sw, LV_BAR_STYLE_BG); break;
|
||||
case LV_SW_STYLE_INDIC: style = lv_bar_get_style(sw, LV_BAR_STYLE_INDIC); break;
|
||||
case LV_SW_STYLE_KNOB_OFF: style = ext->style_knob_off; break;
|
||||
case LV_SW_STYLE_KNOB_ON: style = ext->style_knob_on; break;
|
||||
default: style = NULL; break;
|
||||
@ -250,6 +251,59 @@ uint16_t lv_sw_get_anim_time(const lv_obj_t * sw)
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Handle the drawing related tasks of the sliders
|
||||
* @param sw pointer to an object
|
||||
* @param clip_area the object will be drawn only in this area
|
||||
* @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
|
||||
* (return 'true' if yes)
|
||||
* LV_DESIGN_DRAW: draw the object (always return 'true')
|
||||
* LV_DESIGN_DRAW_POST: drawing after every children are drawn
|
||||
* @param return an element of `lv_design_res_t`
|
||||
*/
|
||||
static lv_design_res_t lv_sw_design(lv_obj_t * sw, const lv_area_t * clip_area, lv_design_mode_t mode)
|
||||
{
|
||||
/*Return false if the object is not covers the mask_p area*/
|
||||
if(mode == LV_DESIGN_COVER_CHK) {
|
||||
return LV_DESIGN_RES_NOT_COVER;
|
||||
}
|
||||
/*Draw the object*/
|
||||
else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
/*The ancestor design function will draw the background and the indicator.
|
||||
* It also sets ext->bar.indic_area*/
|
||||
ancestor_design(sw, clip_area, mode);
|
||||
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(sw);
|
||||
const lv_style_t * style_knob = lv_sw_get_style(sw, ext->state ?
|
||||
LV_SW_STYLE_KNOB_ON : LV_SW_STYLE_KNOB_OFF);
|
||||
|
||||
const lv_style_t * style_indic = lv_sw_get_style(sw, LV_SW_STYLE_INDIC);
|
||||
|
||||
lv_coord_t objw = lv_obj_get_width(sw);
|
||||
lv_coord_t objh = lv_obj_get_height(sw);
|
||||
lv_coord_t indic_maxw = objw - style_indic->body.padding.left - style_indic->body.padding.right;
|
||||
lv_coord_t knob_size = objh;
|
||||
|
||||
lv_coord_t indic_p = (lv_area_get_width(&ext->bar.indic_area) * 256) / (indic_maxw);
|
||||
lv_area_t knob_area;
|
||||
knob_area.x2 = ext->bar.indic_area.x2;
|
||||
knob_area.x2 += (knob_size * (256 - indic_p)) >> 8;
|
||||
if(knob_area.x2 < sw->coords.x1 + knob_size) knob_area.x2 = sw->coords.x1 + knob_size;
|
||||
knob_area.x1 = knob_area.x2 - knob_size;
|
||||
knob_area.y1 = sw->coords.y1;
|
||||
knob_area.y2 = sw->coords.y2;
|
||||
|
||||
lv_draw_rect(&knob_area, clip_area, style_knob, opa_scale);
|
||||
}
|
||||
/*Post draw when the children are drawn*/
|
||||
else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
}
|
||||
|
||||
return LV_DESIGN_RES_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signal function of the switch
|
||||
* @param sw pointer to a switch object
|
||||
@ -261,26 +315,11 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param)
|
||||
{
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
|
||||
/*Save the current (old) value before slider signal modifies it. It will be required in the
|
||||
* later calculations*/
|
||||
int16_t old_val;
|
||||
if(sign == LV_SIGNAL_PRESSING)
|
||||
old_val = ext->slider.drag_value;
|
||||
else
|
||||
old_val = lv_slider_get_value(sw);
|
||||
|
||||
/*Don't let the slider to call the action. Switch handles it differently*/
|
||||
lv_event_cb_t event_cb = sw->event_cb;
|
||||
sw->event_cb = NULL;
|
||||
|
||||
lv_res_t res;
|
||||
/* Include the ancient signal function */
|
||||
|
||||
res = ancestor_signal(sw, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
|
||||
sw->event_cb = event_cb;
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
} else if(sign == LV_SIGNAL_PRESSED) {
|
||||
@ -297,37 +336,42 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param)
|
||||
} else if(sign == LV_SIGNAL_PRESSING) {
|
||||
/*See if the switch was slid (moved at least a little)*/
|
||||
lv_indev_t * indev = lv_indev_get_act();
|
||||
lv_point_t p;
|
||||
if(indev) {
|
||||
lv_point_t p = {0, 0};
|
||||
lv_indev_get_point(indev, &p);
|
||||
if(LV_MATH_ABS(p.x - ext->start_x) > LV_INDEV_DEF_DRAG_LIMIT) ext->slided = 1;
|
||||
}
|
||||
if(LV_MATH_ABS(p.x - ext->start_x) > indev->driver.drag_limit) ext->slided = 1;
|
||||
|
||||
/*If didn't slide then revert the min/max value. So click without slide won't move the
|
||||
* switch as a slider*/
|
||||
if(ext->slided == 0) {
|
||||
if(lv_sw_get_state(sw))
|
||||
ext->slider.drag_value = LV_SW_MAX_VALUE;
|
||||
else
|
||||
ext->slider.drag_value = 0;
|
||||
}
|
||||
/*If slid set the value accordingly*/
|
||||
if(ext->slided) {
|
||||
lv_coord_t w = lv_obj_get_width(sw);
|
||||
const lv_style_t * indic_style = lv_sw_get_style(sw, LV_SW_STYLE_INDIC);
|
||||
int16_t new_val = 0;
|
||||
|
||||
/*If explicitly changed (by slide) don't need to be toggled on release*/
|
||||
int16_t threshold = LV_SW_MAX_VALUE / 2;
|
||||
if((old_val < threshold && ext->slider.drag_value > threshold) ||
|
||||
(old_val > threshold && ext->slider.drag_value < threshold)) {
|
||||
ext->changed = 1;
|
||||
lv_coord_t indic_w = w - indic_style->body.padding.left - indic_style->body.padding.right;
|
||||
int32_t range = ext->bar.max_value - ext->bar.min_value;
|
||||
new_val = p.x - (sw->coords.x1 + indic_style->body.padding.left); /*Make the point relative to the indicator*/
|
||||
new_val = (new_val * range) / indic_w;
|
||||
new_val += ext->bar.min_value;
|
||||
|
||||
if(new_val < ext->bar.min_value) new_val = ext->bar.min_value;
|
||||
else if(new_val > ext->bar.max_value) new_val = ext->bar.max_value;
|
||||
|
||||
/*If explicitly changed (by slide) don't need to be toggled on release*/
|
||||
int16_t threshold = LV_SW_MAX_VALUE / 2;
|
||||
if((new_val < threshold && ext->bar.cur_value > threshold) ||
|
||||
(new_val > threshold && ext->bar.cur_value < threshold)) {
|
||||
ext->changed = 1;
|
||||
}
|
||||
|
||||
if(new_val != ext->bar.cur_value) {
|
||||
ext->bar.cur_value = new_val;
|
||||
lv_obj_invalidate(sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_PRESS_LOST) {
|
||||
if(lv_sw_get_state(sw)) {
|
||||
lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);
|
||||
lv_slider_set_value(sw, LV_SW_MAX_VALUE, LV_ANIM_ON);
|
||||
if(res != LV_RES_OK) return res;
|
||||
} else {
|
||||
lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);
|
||||
lv_slider_set_value(sw, 0, LV_ANIM_ON);
|
||||
if(res != LV_RES_OK) return res;
|
||||
}
|
||||
if(lv_sw_get_state(sw)) lv_sw_on(sw, LV_ANIM_ON);
|
||||
else lv_sw_off(sw, LV_ANIM_ON);
|
||||
} else if(sign == LV_SIGNAL_RELEASED) {
|
||||
/*If not dragged then toggle the switch*/
|
||||
if(ext->changed == 0) {
|
||||
@ -345,7 +389,7 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param)
|
||||
}
|
||||
/*If the switch was dragged then calculate the new state based on the current position*/
|
||||
else {
|
||||
int16_t v = lv_slider_get_value(sw);
|
||||
int16_t v = lv_bar_get_value(sw);
|
||||
int32_t state;
|
||||
if(v > LV_SW_MAX_VALUE / 2) {
|
||||
lv_sw_on(sw, LV_ANIM_ON);
|
||||
@ -361,17 +405,52 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param)
|
||||
char c = *((char *)param);
|
||||
uint32_t state;
|
||||
if(c == LV_KEY_RIGHT || c == LV_KEY_UP) {
|
||||
lv_slider_set_value(sw, LV_SW_MAX_VALUE, true);
|
||||
lv_bar_set_value(sw, LV_SW_MAX_VALUE, LV_ANIM_ON);
|
||||
state = 1;
|
||||
res = lv_event_send(sw, LV_EVENT_VALUE_CHANGED, &state);
|
||||
if(res != LV_RES_OK) return res;
|
||||
} else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) {
|
||||
lv_slider_set_value(sw, 0, true);
|
||||
lv_bar_set_value(sw, 0, LV_ANIM_ON);
|
||||
state = 0;
|
||||
res = lv_event_send(sw, LV_EVENT_VALUE_CHANGED, &state);
|
||||
if(res != LV_RES_OK) return res;
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_GET_EDITABLE) {
|
||||
}
|
||||
else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
|
||||
const lv_style_t * bg_style = lv_sw_get_style(sw, LV_SW_STYLE_BG);
|
||||
const lv_style_t * indic_style = lv_sw_get_style(sw, LV_SW_STYLE_INDIC);
|
||||
const lv_style_t * knob_on_style = lv_sw_get_style(sw, LV_SW_STYLE_KNOB_OFF);
|
||||
const lv_style_t * knob_off_style = lv_sw_get_style(sw, LV_SW_STYLE_KNOB_ON);
|
||||
/* The smaller size is the knob diameter*/
|
||||
lv_coord_t knob_on_size = LV_MATH_MIN(lv_obj_get_width(sw), lv_obj_get_height(sw)) >> 1;
|
||||
knob_on_size += LV_MATH_MAX(
|
||||
LV_MATH_MAX(knob_on_style->body.padding.left, knob_on_style->body.padding.right),
|
||||
LV_MATH_MAX(knob_on_style->body.padding.bottom, knob_on_style->body.padding.top));
|
||||
|
||||
knob_on_size += knob_on_style->body.shadow.width + knob_on_style->body.shadow.spread;
|
||||
knob_on_size += LV_MATH_MAX(LV_MATH_ABS(knob_on_style->body.shadow.offset.x), LV_MATH_ABS(knob_on_style->body.shadow.offset.y));
|
||||
|
||||
lv_coord_t knob_off_size = LV_MATH_MIN(lv_obj_get_width(sw), lv_obj_get_height(sw)) >> 1;
|
||||
knob_off_size += LV_MATH_MAX(
|
||||
LV_MATH_MAX(knob_off_style->body.padding.left, knob_off_style->body.padding.right),
|
||||
LV_MATH_MAX(knob_off_style->body.padding.bottom, knob_off_style->body.padding.top));
|
||||
|
||||
knob_off_size += knob_off_style->body.shadow.width + knob_off_style->body.shadow.spread;
|
||||
knob_off_size += LV_MATH_MAX(LV_MATH_ABS(knob_off_style->body.shadow.offset.x), LV_MATH_ABS(knob_off_style->body.shadow.offset.y));
|
||||
|
||||
lv_coord_t bg_size = bg_style->body.shadow.width + bg_style->body.shadow.spread;
|
||||
bg_size += LV_MATH_MAX(LV_MATH_ABS(bg_style->body.shadow.offset.x), LV_MATH_ABS(bg_style->body.shadow.offset.y));
|
||||
|
||||
lv_coord_t indic_size = indic_style->body.shadow.width + indic_style->body.shadow.spread;
|
||||
indic_size += LV_MATH_MAX(LV_MATH_ABS(indic_style->body.shadow.offset.x), LV_MATH_ABS(indic_style->body.shadow.offset.y));
|
||||
|
||||
sw->ext_draw_pad = LV_MATH_MAX(sw->ext_draw_pad, knob_on_size);
|
||||
sw->ext_draw_pad = LV_MATH_MAX(sw->ext_draw_pad, knob_off_size);
|
||||
sw->ext_draw_pad = LV_MATH_MAX(sw->ext_draw_pad, bg_size);
|
||||
sw->ext_draw_pad = LV_MATH_MAX(sw->ext_draw_pad, indic_size);
|
||||
|
||||
}
|
||||
else if(sign == LV_SIGNAL_GET_EDITABLE) {
|
||||
bool * editable = (bool *)param;
|
||||
*editable = false; /*The ancestor slider is editable the switch is not*/
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
|
@ -27,7 +27,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../lv_core/lv_obj.h"
|
||||
#include "lv_slider.h"
|
||||
#include "lv_bar.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -40,13 +40,14 @@ extern "C" {
|
||||
/*Data of switch*/
|
||||
typedef struct
|
||||
{
|
||||
lv_slider_ext_t slider; /*Ext. of ancestor*/
|
||||
lv_bar_ext_t bar; /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
const lv_style_t * style_knob_off; /**< Style of the knob when the switch is OFF*/
|
||||
const lv_style_t * style_knob_on; /**< Style of the knob when the switch is ON (NULL to use the same as OFF)*/
|
||||
lv_coord_t start_x;
|
||||
uint8_t changed : 1; /*Indicates the switch state explicitly changed by drag*/
|
||||
uint8_t slided : 1;
|
||||
uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/
|
||||
uint8_t slided :1;
|
||||
uint8_t state :1; /*The current state*/
|
||||
#if LV_USE_ANIMATION
|
||||
uint16_t anim_time; /*switch animation time */
|
||||
#endif
|
||||
@ -128,7 +129,8 @@ void lv_sw_set_anim_time(lv_obj_t * sw, uint16_t anim_time);
|
||||
*/
|
||||
static inline bool lv_sw_get_state(const lv_obj_t * sw)
|
||||
{
|
||||
return lv_bar_get_value(sw) < LV_SW_MAX_VALUE / 2 ? false : true;
|
||||
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
|
||||
return ext->state ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
@ -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;
|
||||
|
@ -824,11 +824,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;
|
||||
|
@ -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 ""
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user