diff --git a/CHANGELOG.md b/CHANGELOG.md index cc040fccf..c654be0e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ Available in the `dev` branch - Add `lv_chart_get_x_start_point()` function - Get the current index of the x-axis start point in the data array - Add `lv_chart_get_point_id()` function - Get an individual point value in the chart series directly based on index - Add `ext_buf_assigned` bit field to `lv_chart_series_t` structure - it's true if external buffer is assigned to series +- Add `lv_chart_set_series_axis()` to assign series to primary or secondary axis +- Add `lv_chart_set_y_range()` to allow setting range of secondary y axis (based on `lv_chart_set_range` but extended with an axis parameter) - Allow setting different font for the selected text in `lv_roller` - Add `theme->apply_cb` to replace `theme->apply_xcb` to make it compatible with the MicroPython binding - Add `lv_theme_set_base()` to allow easy extension of built-in (or any) themes. diff --git a/src/lv_api_map.h b/src/lv_api_map.h index cc3f245e8..926e9ec47 100644 --- a/src/lv_api_map.h +++ b/src/lv_api_map.h @@ -176,17 +176,33 @@ static inline lv_obj_t * lv_page_get_scrl(lv_obj_t * page) } #endif + +#endif /*LV_USE_API_EXTENSION_V6*/ + + + + +/*--------------------- + * V7.0 COMPATIBILITY + *--------------------*/ +#if LV_USE_API_EXTENSION_V7 #if LV_USE_WIN static inline lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src) { - return lv_win_add_btn_right(win, img_src); + return lv_win_add_btn_right(win, img_src); } #endif -#endif /*LV_USE_API_EXTENSION_V6*/ +#if LV_USE_CHART +static inline void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax) +{ + lv_chart_set_y_range(chart, LV_CHART_AXIS_PRIMARY_Y, ymin, ymax); +} +#endif +#endif /*LV_USE_API_EXTENSION_V6*/ /********************** * MACROS **********************/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 6c653bf61..f722c0615 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -289,6 +289,9 @@ #ifndef LV_USE_API_EXTENSION_V6 #define LV_USE_API_EXTENSION_V6 1 #endif +#ifndef LV_USE_API_EXTENSION_V7 +#define LV_USE_API_EXTENSION_V7 1 +#endif /*======================== * Image decoder and cache diff --git a/src/lv_widgets/lv_chart.c b/src/lv_widgets/lv_chart.c index 3c8dac17e..96b09e402 100644 --- a/src/lv_widgets/lv_chart.c +++ b/src/lv_widgets/lv_chart.c @@ -27,8 +27,6 @@ #define LV_CHART_PNUM_DEF 10 #define LV_CHART_AXIS_MAJOR_TICK_LEN_COE 1 / 15 #define LV_CHART_AXIS_MINOR_TICK_LEN_COE 2 / 3 -#define LV_CHART_AXIS_PRIMARY_Y 1 -#define LV_CHART_AXIS_SECONDARY_Y 0 #define LV_CHART_LABEL_ITERATOR_FORWARD 1 #define LV_CHART_LABEL_ITERATOR_REVERSE 0 @@ -101,8 +99,12 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy) _lv_ll_init(&ext->series_ll, sizeof(lv_chart_series_t)); - ext->ymin = LV_CHART_YMIN_DEF; - ext->ymax = LV_CHART_YMAX_DEF; + uint8_t i; + for(i = 0; i < _LV_CHART_AXIS_LAST; i++) { + ext->ymin[i] = LV_CHART_YMIN_DEF; + ext->ymax[i] = LV_CHART_YMAX_DEF; + } + ext->hdiv_cnt = LV_CHART_HDIV_DEF; ext->vdiv_cnt = LV_CHART_VDIV_DEF; ext->point_cnt = LV_CHART_PNUM_DEF; @@ -118,7 +120,6 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy) ext->secondary_y_axis.major_tick_len = LV_CHART_TICK_LENGTH_AUTO; ext->secondary_y_axis.minor_tick_len = LV_CHART_TICK_LENGTH_AUTO; - lv_style_list_init(&ext->style_series_bg); lv_style_list_init(&ext->style_series); @@ -133,7 +134,6 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy) lv_obj_set_size(chart, LV_DPI * 3, LV_DPI * 2); lv_theme_apply(chart, LV_THEME_CHART); - } else { lv_chart_ext_t * ext_copy = lv_obj_get_ext_attr(copy); @@ -142,11 +142,11 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy) lv_style_list_copy(&ext->style_series_bg, &ext_copy->style_series_bg); ext->type = ext_copy->type; - ext->ymin = ext_copy->ymin; - ext->ymax = ext_copy->ymax; ext->hdiv_cnt = ext_copy->hdiv_cnt; ext->vdiv_cnt = ext_copy->vdiv_cnt; ext->point_cnt = ext_copy->point_cnt; + _lv_memcpy_small(ext->ymin, ext_copy->ymin, sizeof(ext->ymin)); + _lv_memcpy_small(ext->ymax, ext_copy->ymax, sizeof(ext->ymax)); _lv_memcpy(&ext->x_axis, &ext_copy->x_axis, sizeof(lv_chart_axis_cfg_t)); _lv_memcpy(&ext->y_axis, &ext_copy->y_axis, sizeof(lv_chart_axis_cfg_t)); _lv_memcpy(&ext->secondary_y_axis, &ext_copy->secondary_y_axis, sizeof(lv_chart_axis_cfg_t)); @@ -192,6 +192,7 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color) ser->start_point = 0; ser->ext_buf_assigned = false; + ser->y_axis = LV_CHART_AXIS_PRIMARY_Y; uint16_t i; lv_coord_t * p_tmp = ser->points; @@ -249,20 +250,26 @@ void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv) } /** - * Set the minimal and maximal y values + * Set the minimal and maximal y values on an axis * @param chart pointer to a graph background object + * @param axis `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` * @param ymin y minimum value * @param ymax y maximum value */ -void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax) +void lv_chart_set_y_range(lv_obj_t * chart, lv_chart_axis_t axis, lv_coord_t ymin, lv_coord_t ymax) { LV_ASSERT_OBJ(chart, LV_OBJX_NAME); - lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); - if(ext->ymin == ymin && ext->ymax == ymax) return; + if(axis >= _LV_CHART_AXIS_LAST) { + LV_LOG_WARN("Invalid axis: %d", axis); + return; + } - ext->ymin = ymin; - ext->ymax = ymax; + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->ymin[axis] == ymin && ext->ymax[axis] == ymax) return; + + ext->ymin[axis] = ymin; + ext->ymax[axis] = ymax; lv_chart_refresh(chart); } @@ -600,6 +607,28 @@ void lv_chart_set_point_id(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t ser->points[id] = value; } +/** + * Set the Y axis of a series + * @param chart pointer to a chart object + * @param ser pointer to series + * @param axis `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` + */ +void lv_chart_set_series_axis(lv_obj_t * chart, lv_chart_series_t * ser, lv_chart_axis_t axis) +{ + LV_ASSERT_OBJ(chart, LV_OBJX_NAME); + LV_ASSERT_NULL(ser); + + if(axis >= _LV_CHART_AXIS_LAST) { + LV_LOG_WARN("Invalid axis: %d", axis); + return; + } + + if( ser->y_axis == axis) return; + + ser->y_axis = axis; + lv_chart_refresh(chart); +} + /*===================== * Getter functions *====================*/ @@ -660,6 +689,19 @@ lv_coord_t lv_chart_get_point_id(lv_obj_t * chart, lv_chart_series_t * ser, uint } +/** + * Get the Y axis of a series + * @param chart pointer to a chart object + * @param ser pointer to series + * @return `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` + */ +lv_chart_axis_t lv_chart_get_series_axis(lv_obj_t * chart, lv_chart_series_t * ser) +{ + LV_ASSERT_NULL(ser); + LV_UNUSED(chart); + + return ser->y_axis; +} /*===================== * Other functions *====================*/ @@ -929,8 +971,8 @@ static void draw_series_line(lv_obj_t * chart, const lv_area_t * series_area, co lv_coord_t p_act = start_point; lv_coord_t p_prev = start_point; - int32_t y_tmp = (int32_t)((int32_t)ser->points[p_prev] - ext->ymin) * h; - y_tmp = y_tmp / (ext->ymax - ext->ymin); + int32_t y_tmp = (int32_t)((int32_t)ser->points[p_prev] - ext->ymin[ser->y_axis]) * h; + y_tmp = y_tmp / (ext->ymax[ser->y_axis] - ext->ymin[ser->y_axis]); p2.y = h - y_tmp + y_ofs; for(i = 0; i < ext->point_cnt; i++) { @@ -941,8 +983,8 @@ static void draw_series_line(lv_obj_t * chart, const lv_area_t * series_area, co p_act = (start_point + i) % ext->point_cnt; - y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h; - y_tmp = y_tmp / (ext->ymax - ext->ymin); + y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin[ser->y_axis]) * h; + y_tmp = y_tmp / (ext->ymax[ser->y_axis] - ext->ymin[ser->y_axis]); p2.y = h - y_tmp + y_ofs; /*Don't draw the first point. A second point is also required to draw the line*/ @@ -1065,8 +1107,8 @@ static void draw_series_column(lv_obj_t * chart, const lv_area_t * series_area, col_dsc.bg_color = ser->color; lv_coord_t p_act = (start_point + i) % ext->point_cnt; - y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h; - y_tmp = y_tmp / (ext->ymax - ext->ymin); + y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin[ser->y_axis]) * h; + y_tmp = y_tmp / (ext->ymax[ser->y_axis] - ext->ymin[ser->y_axis]); col_a.y1 = h - y_tmp + series_area->y1; if(ser->points[p_act] != LV_CHART_POINT_DEF) { diff --git a/src/lv_widgets/lv_chart.h b/src/lv_widgets/lv_chart.h index 87dc201b3..06bbe84a2 100644 --- a/src/lv_widgets/lv_chart.h +++ b/src/lv_widgets/lv_chart.h @@ -52,11 +52,20 @@ enum { }; typedef uint8_t lv_chart_update_mode_t; + +enum { + LV_CHART_AXIS_PRIMARY_Y, + LV_CHART_AXIS_SECONDARY_Y, + _LV_CHART_AXIS_LAST, +}; +typedef uint8_t lv_chart_axis_t; + typedef struct { lv_coord_t * points; lv_color_t color; uint16_t start_point; uint8_t ext_buf_assigned : 1; + lv_chart_axis_t y_axis : 1; } lv_chart_series_t; /** Data of axis */ @@ -80,8 +89,8 @@ typedef struct { /*No inherited ext*/ /*Ext. of ancestor*/ /*New data for this type */ lv_ll_t series_ll; /*Linked list for the data line pointers (stores lv_chart_series_t)*/ - lv_coord_t ymin; /*y min value (used to scale the data)*/ - lv_coord_t ymax; /*y max value (used to scale the data)*/ + lv_coord_t ymin[_LV_CHART_AXIS_LAST]; /*y min values for both axis (used to scale the data)*/ + lv_coord_t ymax[_LV_CHART_AXIS_LAST]; /*y max values for both axis (used to scale the data)*/ uint8_t hdiv_cnt; /*Number of horizontal division lines*/ uint8_t vdiv_cnt; /*Number of vertical division lines*/ uint16_t point_cnt; /*Point number in a data line*/ @@ -137,6 +146,7 @@ void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); * Setter functions *====================*/ + /** * Set the number of horizontal and vertical division lines * @param chart pointer to a graph background object @@ -146,12 +156,13 @@ void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv); /** - * Set the minimal and maximal y values + * Set the minimal and maximal y values on an axis * @param chart pointer to a graph background object + * @param axis `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` * @param ymin y minimum value * @param ymax y maximum value */ -void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax); +void lv_chart_set_y_range(lv_obj_t * chart, lv_chart_axis_t axis, lv_coord_t ymin, lv_coord_t ymax); /** * Set a new type for a chart @@ -287,6 +298,14 @@ void lv_chart_set_ext_array(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_ */ void lv_chart_set_point_id(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t value, uint16_t id); +/** + * Set the Y axis of a series + * @param chart pointer to a chart object + * @param ser pointer to series + * @param axis `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` + */ +void lv_chart_set_series_axis(lv_obj_t * chart, lv_chart_series_t * ser, lv_chart_axis_t axis); + /*===================== * Getter functions *====================*/ @@ -321,6 +340,14 @@ uint16_t lv_chart_get_x_start_point(lv_chart_series_t * ser); */ lv_coord_t lv_chart_get_point_id(lv_obj_t * chart, lv_chart_series_t * ser, uint16_t id); +/** + * Get the Y axis of a series + * @param chart pointer to a chart object + * @param ser pointer to series + * @return `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` + */ +lv_chart_axis_t lv_chart_get_series_axis(lv_obj_t * chart, lv_chart_series_t * ser); + /*===================== * Other functions *====================*/