diff --git a/src/lv_objx/lv_gauge.c b/src/lv_objx/lv_gauge.c index a15ab1e7f..d24e83673 100644 --- a/src/lv_objx/lv_gauge.c +++ b/src/lv_objx/lv_gauge.c @@ -15,6 +15,7 @@ #include "../lv_misc/lv_txt.h" #include "../lv_misc/lv_math.h" #include "../lv_misc/lv_utils.h" +#include "lv_img.h" #include #include @@ -27,8 +28,6 @@ #define LV_GAUGE_DEF_LABEL_COUNT 6 #define LV_GAUGE_DEF_LINE_COUNT 21 /*Should be: ((label_cnt - 1) * internal_lines) + 1*/ #define LV_GAUGE_DEF_ANGLE 220 -#define LV_GAUGE_INTERPOLATE_SHIFT 5 /*Interpolate the needle drawing between to degrees*/ -#define LV_GAUGE_INTERPOLATE_MASK 0x1F /********************** * TYPEDEFS @@ -40,7 +39,7 @@ static lv_design_res_t lv_gauge_design(lv_obj_t * gauge, const lv_area_t * clip_area, lv_design_mode_t mode); static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param); static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask); -static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask); +static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * clip_area); /********************** * STATIC VARIABLES @@ -81,6 +80,10 @@ lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy) ext->values = NULL; ext->needle_colors = NULL; ext->label_count = LV_GAUGE_DEF_LABEL_COUNT; + + ext->needle_img = 0; + ext->needle_img_pivot.x = 0; + ext->needle_img_pivot.y = 0; if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_gauge); if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(new_gauge); @@ -194,8 +197,8 @@ void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value) * @param gauge pointer to a gauge object * @param angle angle of the scale (0..360) * @param line_cnt count of scale lines. - * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + - * 1 + * To get a given "subdivision" lines between labels: + * `line_cnt = (sub_div + 1) * (label_cnt - 1) + 1 ` * @param label_cnt count of scale labels. */ void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt) @@ -209,6 +212,28 @@ void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint lv_obj_invalidate(gauge); } +/** + * Set an image to display as needle(s). + * The needle image should be horizontal and pointing to the right (`--->`). + * @param gauge pointer to a gauge object + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) + * @param pivot_x the X coordinate of rotation center of the image + * @param pivot_y the Y coordinate of rotation center of the image + */ +void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivot_x, lv_coord_t pivot_y) +{ + LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + ext->needle_img = img; + ext->needle_img_pivot.x = pivot_x; + ext->needle_img_pivot.y = pivot_y; + + lv_obj_invalidate(gauge); +} + /*===================== * Getter functions *====================*/ @@ -257,6 +282,50 @@ uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge) return ext->label_count; } +/** + * Get an image to display as needle(s). + * @param gauge pointer to a gauge object + * @return pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object). `NULL` if not used. + */ +const void * lv_gauge_get_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivot_x, lv_coord_t pivot_y) +{ + LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + return ext->needle_img; +} + +/** + * Get the X coordinate of the rotation center of the needle image + * @param gauge pointer to a gauge object + * @return the X coordinate of rotation center of the image + */ +lv_coord_t lv_gauge_get_needle_img_pivot_x(lv_obj_t * gauge) +{ + LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + return ext->needle_img_pivot.x; +} + +/** + * Get the Y coordinate of the rotation center of the needle image + * @param gauge pointer to a gauge object + * @return the X coordinate of rotation center of the image + */ +lv_coord_t lv_gauge_get_needle_img_pivot_y(lv_obj_t * gauge) +{ + LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + return ext->needle_img_pivot.y; +} + + /********************** * STATIC FUNCTIONS **********************/ @@ -397,7 +466,7 @@ static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask) * @param gauge pointer to gauge object * @param mask mask of drawing */ -static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask) +static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * clip_area) { lv_style_t style_needle; lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); @@ -413,45 +482,48 @@ static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask) int16_t max = lv_gauge_get_max_value(gauge); lv_point_t p_mid; lv_point_t p_end; - lv_point_t p_end_low; - lv_point_t p_end_high; uint8_t i; lv_style_copy(&style_needle, style); + if(ext->needle_colors != NULL) { + style_needle.image.intense = LV_OPA_COVER; + } p_mid.x = x_ofs; p_mid.y = y_ofs; for(i = 0; i < ext->needle_count; i++) { /*Calculate the end point of a needle*/ + int16_t needle_angle = - (ext->values[i] - min) * angle * (1 << LV_GAUGE_INTERPOLATE_SHIFT) / (max - min); + (ext->values[i] - min) * angle / (max - min) + angle_ofs; - int16_t needle_angle_low = (needle_angle >> LV_GAUGE_INTERPOLATE_SHIFT) + angle_ofs; - int16_t needle_angle_high = needle_angle_low + 1; + /*Draw line*/ + if(ext->needle_img == NULL) { + p_end.y = (lv_trigo_sin(needle_angle) * r) / LV_TRIGO_SIN_MAX + y_ofs; + p_end.x = (lv_trigo_sin(needle_angle + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; - p_end_low.y = (lv_trigo_sin(needle_angle_low) * r) / LV_TRIGO_SIN_MAX + y_ofs; - p_end_low.x = (lv_trigo_sin(needle_angle_low + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; + /*Draw the needle with the corresponding color*/ + if(ext->needle_colors != NULL) + style_needle.line.color = ext->needle_colors[i]; - p_end_high.y = (lv_trigo_sin(needle_angle_high) * r) / LV_TRIGO_SIN_MAX + y_ofs; - p_end_high.x = (lv_trigo_sin(needle_angle_high + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; + lv_draw_line(&p_mid, &p_end, clip_area, &style_needle, opa_scale); + } + /*Draw image*/ + else { + lv_img_header_t info; + lv_img_decoder_get_info(ext->needle_img, &info); - uint16_t rem = needle_angle & ((1 << LV_GAUGE_INTERPOLATE_SHIFT) - 1); - int16_t x_mod = ((LV_MATH_ABS(p_end_high.x - p_end_low.x)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT; - int16_t y_mod = ((LV_MATH_ABS(p_end_high.y - p_end_low.y)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT; + lv_area_t a; + a.x1 = gauge->coords.x1 + lv_area_get_width(&gauge->coords) / 2 - ext->needle_img_pivot.x; + a.y1 = gauge->coords.y1 + lv_area_get_height(&gauge->coords) / 2 - ext->needle_img_pivot.y; + a.x2 = a.x1 + info.w - 1; + a.y2 = a.y1 + info.h - 1; - if(p_end_high.x < p_end_low.x) x_mod = -x_mod; - if(p_end_high.y < p_end_low.y) y_mod = -y_mod; + if(ext->needle_colors != NULL) + style_needle.image.color = ext->needle_colors[i]; - p_end.x = p_end_low.x + x_mod; - p_end.y = p_end_low.y + y_mod; - - /*Draw the needle with the corresponding color*/ - if(ext->needle_colors == NULL) - style_needle.line.color = LV_GAUGE_DEF_NEEDLE_COLOR; - else - style_needle.line.color = ext->needle_colors[i]; - - lv_draw_line(&p_mid, &p_end, mask, &style_needle, opa_scale); + lv_draw_img(&a, clip_area, ext->needle_img, &style_needle, needle_angle, &ext->needle_img_pivot, LV_IMG_ZOOM_NONE, true, opa_scale); + } } /*Draw the needle middle area*/ @@ -467,7 +539,7 @@ static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask) nm_cord.x2 = x_ofs + style->body.radius; nm_cord.y2 = y_ofs + style->body.radius; - lv_draw_rect(&nm_cord, mask, &style_neddle_mid, lv_obj_get_opa_scale(gauge)); + lv_draw_rect(&nm_cord, clip_area, &style_neddle_mid, lv_obj_get_opa_scale(gauge)); } #endif diff --git a/src/lv_objx/lv_gauge.h b/src/lv_objx/lv_gauge.h index fb7cf366a..6b03a8404 100644 --- a/src/lv_objx/lv_gauge.h +++ b/src/lv_objx/lv_gauge.h @@ -46,6 +46,8 @@ typedef struct /*New data for this type */ int16_t * values; /*Array of the set values (for needles) */ const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ + const void * needle_img; + lv_point_t needle_img_pivot; uint8_t needle_count; /*Number of needles*/ uint8_t label_count; /*Number of labels on the scale*/ } lv_gauge_ext_t; @@ -114,12 +116,23 @@ static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) * @param gauge pointer to a gauge object * @param angle angle of the scale (0..360) * @param line_cnt count of scale lines. - * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + - * 1 + * To get a given "subdivision" lines between labels: + * `line_cnt = (sub_div + 1) * (label_cnt - 1) + 1 ` * @param label_cnt count of scale labels. */ void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt); +/** + * Set an image to display as needle(s). + * The needle image should be horizontal and pointing to the right (`--->`). + * @param gauge pointer to a gauge object + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) + * @param pivot_x the X coordinate of rotation center of the image + * @param pivot_y the Y coordinate of rotation center of the image + */ +void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivot_x, lv_coord_t pivot_y); + /** * Set the styles of a gauge * @param gauge pointer to a gauge object @@ -208,6 +221,28 @@ static inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge) return lv_lmeter_get_scale_angle(gauge); } +/** + * Get an image to display as needle(s). + * @param gauge pointer to a gauge object + * @return pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object). `NULL` if not used. + */ +const void * lv_gauge_get_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivot_x, lv_coord_t pivot_y); + +/** + * Get the X coordinate of the rotation center of the needle image + * @param gauge pointer to a gauge object + * @return the X coordinate of rotation center of the image + */ +lv_coord_t lv_gauge_get_needle_img_pivot_x(lv_obj_t * gauge); + +/** + * Get the Y coordinate of the rotation center of the needle image + * @param gauge pointer to a gauge object + * @return the X coordinate of rotation center of the image + */ +lv_coord_t lv_gauge_get_needle_img_pivot_y(lv_obj_t * gauge); + /** * Get the style of a gauge * @param gauge pointer to a gauge object diff --git a/src/lv_objx/lv_lmeter.c b/src/lv_objx/lv_lmeter.c index a8b0bb629..0ef1f3237 100644 --- a/src/lv_objx/lv_lmeter.c +++ b/src/lv_objx/lv_lmeter.c @@ -20,9 +20,6 @@ *********************/ #define LV_OBJX_NAME "lv_lmeter" -#define LV_LMETER_LINE_UPSCALE 5 /*2^x upscale of line to make rounding*/ -#define LV_LMETER_LINE_UPSCALE_MASK ((1 << LV_LMETER_LINE_UPSCALE) - 1) - /********************** * TYPEDEFS **********************/ @@ -32,7 +29,6 @@ **********************/ static lv_design_res_t lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * clip_area, lv_design_mode_t mode); static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param); -static lv_coord_t lv_lmeter_coord_round(int32_t x); /********************** * STATIC VARIABLES @@ -273,6 +269,7 @@ uint16_t lv_lmeter_get_angle_offset(lv_obj_t * lmeter) return ext->angle_ofs; } + /********************** * STATIC FUNCTIONS **********************/ @@ -321,24 +318,27 @@ static lv_design_res_t lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * cli style_tmp.line.color = style->body.main_color; - /*Calculate every coordinate in a bigger size to make rounding later*/ - r_out = r_out << LV_LMETER_LINE_UPSCALE; - r_in = r_in << LV_LMETER_LINE_UPSCALE; - for(i = 0; i < ext->line_cnt; i++) { /*Calculate the position a scale label*/ int16_t angle = (i * ext->scale_angle) / (ext->line_cnt - 1) + angle_ofs; - lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) >> LV_TRIGO_SHIFT; - lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) >> LV_TRIGO_SHIFT; - lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) >> LV_TRIGO_SHIFT; - lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) >> LV_TRIGO_SHIFT; + lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) >> (LV_TRIGO_SHIFT - 8); + lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) >> (LV_TRIGO_SHIFT - 8); + lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) >> (LV_TRIGO_SHIFT - 8); + lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) >> (LV_TRIGO_SHIFT - 8); /*Rounding*/ - x_out = lv_lmeter_coord_round(x_out); - x_in = lv_lmeter_coord_round(x_in); - y_out = lv_lmeter_coord_round(y_out); - y_in = lv_lmeter_coord_round(y_in); + if(x_out <= 0) x_out = (x_out + 127) >> 8; + else x_out = (x_out - 127) >> 8; + + if(x_in <= 0) x_in = (x_in + 127) >> 8; + else x_in = (x_in - 127) >> 8; + + if(y_out <= 0) y_out = (y_out + 127) >> 8; + else y_out = (y_out - 127) >> 8; + + if(y_in <= 0) y_in = (y_in + 127) >> 8; + else y_in = (y_in - 127) >> 8; lv_point_t p1; lv_point_t p2; @@ -394,29 +394,4 @@ static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * par return res; } - -/** - * Round a coordinate which is upscaled (>=x.5 -> x + 1; x) - * @param x a coordinate which is greater then it should be - * @return the downscaled and rounded coordinate (+-1) - */ -static lv_coord_t lv_lmeter_coord_round(int32_t x) -{ -#if LV_LMETER_LINE_UPSCALE > 0 - bool was_negative = false; - if(x < 0) { - was_negative = true; - x = -x; - } - - x = (x >> LV_LMETER_LINE_UPSCALE) + ((x & LV_LMETER_LINE_UPSCALE_MASK) >> (LV_LMETER_LINE_UPSCALE - 1)); - - if(was_negative) x = -x; - - return x; -#else - return x; -#endif -} - #endif diff --git a/src/lv_objx/lv_slider.c b/src/lv_objx/lv_slider.c index 7c88df3ce..c9a123a7b 100644 --- a/src/lv_objx/lv_slider.c +++ b/src/lv_objx/lv_slider.c @@ -113,7 +113,8 @@ lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy) /** * Set an image to display on the knob of the slider * @param slider pointer to a slider object - * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ void lv_slider_set_knob_img(lv_obj_t * slider, const void * img_src) { diff --git a/src/lv_objx/lv_slider.h b/src/lv_objx/lv_slider.h index c78aee3d1..e629d1851 100644 --- a/src/lv_objx/lv_slider.h +++ b/src/lv_objx/lv_slider.h @@ -107,6 +107,7 @@ static inline void lv_slider_set_anim_time(lv_obj_t * slider, uint16_t anim_time * Set an image to display on the knob of the slider * @param slider pointer to a slider object * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ void lv_slider_set_knob_img(lv_obj_t * slider, const void * img_src); diff --git a/src/lv_objx/lv_sw.c b/src/lv_objx/lv_sw.c index c81fbecb4..3ea3b5d01 100644 --- a/src/lv_objx/lv_sw.c +++ b/src/lv_objx/lv_sw.c @@ -184,7 +184,8 @@ bool lv_sw_toggle(lv_obj_t * sw, lv_anim_enable_t anim) /** * Set an image to display on the knob of the switch when it's in OFF state * @param sw pointer to a switch object - * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ void lv_sw_set_knob_off_img(lv_obj_t * sw, const void * img_src) { @@ -200,7 +201,8 @@ void lv_sw_set_knob_off_img(lv_obj_t * sw, const void * img_src) /** * Set an image to display on the knob of the switch when it's in ON state * @param sw pointer to a switch object - * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ void lv_sw_set_knob_on_img(lv_obj_t * sw, const void * img_src) { @@ -248,7 +250,8 @@ void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, const lv_style_t * style /** * Get an image to display on the knob of the switch when it's in OFF state * @param sw pointer to a switch object - * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ const void * lv_slider_get_knob_off_img(lv_obj_t * sw, const void * img_src) { @@ -262,7 +265,8 @@ const void * lv_slider_get_knob_off_img(lv_obj_t * sw, const void * img_src) /** * Get an image to display on the knob of the switch when it's in ON state * @param sw pointer to a switch object - * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ const void * lv_slider_get_knob_on_img(lv_obj_t * sw, const void * img_src) { diff --git a/src/lv_objx/lv_sw.h b/src/lv_objx/lv_sw.h index 5f4d3bdca..d7c3939d6 100644 --- a/src/lv_objx/lv_sw.h +++ b/src/lv_objx/lv_sw.h @@ -104,14 +104,16 @@ bool lv_sw_toggle(lv_obj_t * sw, lv_anim_enable_t anim); /** * Set an image to display on the knob of the switch when it's in OFF state * @param sw pointer to a switch object - * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ void lv_sw_set_knob_off_img(lv_obj_t * sw, const void * img_src); /** * Set an image to display on the knob of the switch when it's in ON state * @param sw pointer to a switch object - * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ void lv_sw_set_knob_on_img(lv_obj_t * sw, const void * img_src); @@ -151,14 +153,16 @@ static inline bool lv_sw_get_state(const lv_obj_t * sw) /** * Get an image to display on the knob of the switch when it's in OFF state * @param sw pointer to a switch object - * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ const void * lv_slider_get_knob_off_img(lv_obj_t * sw, const void * img_src); /** * Get an image to display on the knob of the switch when it's in ON state * @param sw pointer to a switch object - * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image (not an `lv_img` object) + * @return the image source: pointer to an `lv_img_dsc_t` variable or a path to an image + * (not an `lv_img` object) */ const void * lv_slider_get_knob_on_img(lv_obj_t * sw, const void * img_src); /**