1 /**
2  * @file lv_demo_high_res_app_smart_meter.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_demo_high_res_private.h"
11 #if LV_USE_DEMO_HIGH_RES
12 
13 #include "../../src/widgets/image/lv_image.h"
14 #include "../../src/widgets/label/lv_label.h"
15 #include "../../src/widgets/chart/lv_chart_private.h"
16 #include "../../src/core/lv_obj_private.h"
17 #include "../../src/draw/lv_draw_private.h"
18 #include "../../src/misc/lv_math.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 
24 #define WIDGET3_POINT_COUNT 24
25 #define WIDGET3_ANIM_RANGE_END 10000
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 typedef struct {
32     int32_t current[WIDGET3_POINT_COUNT];
33     int32_t start[WIDGET3_POINT_COUNT];
34 } widget3_chart_anim_values_t;
35 
36 /**********************
37  *  STATIC PROTOTYPES
38  **********************/
39 
40 static void back_clicked_cb(lv_event_t * e);
41 static lv_obj_t * create_widget1_part(lv_demo_high_res_ctx_t * c, lv_obj_t * parent, const char * title_val,
42                                       const char * daily_val, const char * weekly_val);
43 static void widget1_anim_height_range(lv_demo_high_res_ctx_t * c, int32_t * min, int32_t * max);
44 static void widget1_open_part1_anim_cb(void * arg, int32_t val);
45 static void widget1_open_part2_anim_cb(void * arg, int32_t val);
46 static void widget1_clicked_cb(lv_event_t * e);
47 static void create_widget1(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets);
48 static lv_obj_t * widget23_chart_label(lv_demo_high_res_ctx_t * c, lv_obj_t * parent, const char * text);
49 static void widget2_chart_event_draw_task_cb(lv_event_t * e);
50 static void widget2_chart_bar_clicked_cb(lv_event_t * e);
51 static void widget2_chart_selected_day_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
52 static void create_widget2(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets);
53 static void widget3_chart_draw_task_event_cb(lv_event_t * e);
54 static void widget3_chart_free_anim_values(lv_event_t * e);
55 static void widget3_chart_anim_cb(void * var, int32_t v);
56 static void widget3_chart_selected_day_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
57 static lv_obj_t * create_widget3_stat(lv_demo_high_res_ctx_t * c, lv_obj_t * parent, const char * title_val,
58                                       const char * kwh_val, const char * detail_val);
59 static void create_widget3(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets);
60 
61 /**********************
62  *  STATIC VARIABLES
63  **********************/
64 
65 /**********************
66  *      MACROS
67  **********************/
68 
69 /**********************
70  *   GLOBAL FUNCTIONS
71  **********************/
72 
lv_demo_high_res_app_smart_meter(lv_obj_t * base_obj)73 void lv_demo_high_res_app_smart_meter(lv_obj_t * base_obj)
74 {
75     lv_demo_high_res_ctx_t * c = lv_obj_get_user_data(base_obj);
76 
77     /* background */
78 
79     lv_obj_t * bg = base_obj;
80     lv_obj_remove_style_all(bg);
81     lv_obj_set_size(bg, LV_PCT(100), LV_PCT(100));
82 
83     lv_obj_t * bg_img = lv_image_create(bg);
84     lv_subject_add_observer_obj(&c->th, lv_demo_high_res_theme_observer_image_src_cb, bg_img,
85                                 &c->imgs[IMG_LIGHT_BG_SMART_METER]);
86 
87     lv_obj_t * bg_cont = lv_obj_create(bg);
88     lv_obj_remove_style_all(bg_cont);
89     lv_obj_set_size(bg_cont, LV_PCT(100), LV_PCT(100));
90     lv_obj_set_style_pad_top(bg_cont, c->sz->gap[7], 0);
91     int32_t app_padding = c->sz == &lv_demo_high_res_sizes_all[SIZE_SM] ? c->sz->gap[9] : c->sz->gap[10];
92     lv_obj_set_style_pad_bottom(bg_cont, app_padding, 0);
93     lv_obj_set_style_pad_hor(bg_cont, app_padding, 0);
94 
95     /* top margin */
96 
97     lv_obj_t * top_margin = lv_demo_high_res_top_margin_create(bg_cont, 0, true, c);
98 
99     /* app info */
100 
101     lv_obj_t * app_info = lv_demo_high_res_simple_container_create(bg_cont, true, c->sz->gap[4], LV_FLEX_ALIGN_START);
102     lv_obj_align_to(app_info, top_margin, LV_ALIGN_OUT_BOTTOM_LEFT, 0, c->sz->gap[7]);
103 
104     lv_obj_t * back = lv_demo_high_res_simple_container_create(app_info, false, c->sz->gap[2], LV_FLEX_ALIGN_CENTER);
105     lv_obj_add_event_cb(back, back_clicked_cb, LV_EVENT_CLICKED, NULL);
106 
107     lv_obj_t * back_icon = lv_image_create(back);
108     lv_image_set_src(back_icon, c->imgs[IMG_ARROW_LEFT]);
109     lv_obj_add_style(back_icon, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_A8_IMG], 0);
110     lv_obj_add_flag(back_icon, LV_OBJ_FLAG_EVENT_BUBBLE);
111 
112     lv_obj_t * back_label = lv_label_create(back);
113     lv_label_set_text_static(back_label, "Back");
114     lv_obj_set_style_text_opa(back_label, LV_OPA_60, 0);
115     lv_obj_add_style(back_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
116     lv_obj_add_style(back_label, &c->fonts[FONT_HEADING_MD], 0);
117 
118     lv_obj_t * app_label = lv_label_create(app_info);
119     lv_label_set_text_static(app_label, "Smart Meter");
120     lv_obj_add_style(app_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
121     lv_obj_add_style(app_label, &c->fonts[FONT_HEADING_LG], 0);
122 
123     /* widgets */
124 
125     int32_t widget_gap_padding = c->sz == &lv_demo_high_res_sizes_all[SIZE_SM] ? c->sz->gap[4] : c->sz->gap[7];
126     lv_obj_t * widgets = lv_demo_high_res_simple_container_create(bg_cont, false, widget_gap_padding, LV_FLEX_ALIGN_END);
127     lv_obj_set_align(widgets, LV_ALIGN_BOTTOM_RIGHT);
128 
129     create_widget1(c, widgets);
130     create_widget2(c, widgets);
131     create_widget3(c, widgets);
132 }
133 
134 /**********************
135  *   STATIC FUNCTIONS
136  **********************/
137 
back_clicked_cb(lv_event_t * e)138 static void back_clicked_cb(lv_event_t * e)
139 {
140     lv_obj_t * back = lv_event_get_target_obj(e);
141 
142     lv_obj_t * base_obj = lv_obj_get_parent(lv_obj_get_parent(lv_obj_get_parent(back)));
143     lv_obj_clean(base_obj);
144     lv_demo_high_res_home(base_obj);
145 }
146 
create_widget1_part(lv_demo_high_res_ctx_t * c,lv_obj_t * parent,const char * title_val,const char * daily_val,const char * weekly_val)147 static lv_obj_t * create_widget1_part(lv_demo_high_res_ctx_t * c, lv_obj_t * parent, const char * title_val,
148                                       const char * daily_val, const char * weekly_val)
149 {
150     lv_obj_t * part = lv_obj_create(parent);
151     lv_obj_remove_style_all(part);
152     lv_obj_remove_flag(part, LV_OBJ_FLAG_SCROLLABLE);
153     lv_subject_add_observer_obj(&c->th, lv_demo_high_res_theme_observer_obj_bg_image_src_cb, part,
154                                 &c->imgs[IMG_LIGHT_WIDGET1_BG]);
155     lv_obj_set_style_bg_color(part, lv_color_white(), 0);
156     lv_obj_set_style_bg_opa(part, LV_OPA_COVER, 0);
157     lv_obj_set_style_radius(part, c->sz->card_radius, 0);
158     lv_obj_set_width(part, LV_PCT(100));
159     lv_obj_set_style_pad_all(part, c->sz->gap[7], 0);
160     lv_obj_set_style_clip_corner(part, true, 0);
161 
162     lv_obj_t * title = lv_label_create(part);
163     lv_label_set_text_static(title, title_val);
164     lv_obj_add_style(title, &c->fonts[FONT_LABEL_MD], 0);
165 
166     lv_obj_t * box = lv_obj_create(part);
167     lv_obj_remove_style_all(box);
168     lv_obj_add_flag(box, LV_OBJ_FLAG_EVENT_BUBBLE);
169     lv_obj_set_size(box, LV_PCT(100), LV_SIZE_CONTENT);
170     lv_obj_set_align(box, LV_ALIGN_BOTTOM_MID);
171     lv_obj_set_flex_flow(box, LV_FLEX_FLOW_ROW);
172     lv_obj_set_flex_align(box, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
173 
174     lv_obj_t * daily_box = lv_demo_high_res_simple_container_create(box, true, c->sz->gap[2], LV_FLEX_ALIGN_START);
175     lv_obj_add_flag(daily_box, LV_OBJ_FLAG_EVENT_BUBBLE);
176 
177     lv_obj_t * daily_label = lv_label_create(daily_box);
178     lv_label_set_text_static(daily_label, "Daily");
179     lv_obj_add_style(daily_label, &c->fonts[FONT_LABEL_SM], 0);
180     lv_obj_set_style_text_color(daily_label, lv_color_black(), 0);
181 
182     lv_obj_t * daily_value_box = lv_demo_high_res_simple_container_create(daily_box, false, c->sz->gap[1],
183                                                                           LV_FLEX_ALIGN_END);
184     lv_obj_add_flag(daily_value_box, LV_OBJ_FLAG_EVENT_BUBBLE);
185 
186     lv_obj_t * daily_value_label = lv_label_create(daily_value_box);
187     lv_label_set_text_static(daily_value_label, daily_val);
188     lv_obj_add_style(daily_value_label, &c->fonts[FONT_LABEL_LG], 0);
189     lv_obj_set_style_text_color(daily_value_label, lv_color_black(), 0);
190     lv_obj_t * daily_kwh_label = lv_label_create(daily_value_box);
191     lv_label_set_text_static(daily_kwh_label, "kWh");
192     lv_obj_add_style(daily_kwh_label, &c->fonts[FONT_LABEL_SM], 0);
193     lv_obj_set_style_text_color(daily_kwh_label, lv_color_black(), 0);
194     lv_obj_set_style_text_opa(daily_kwh_label, LV_OPA_40, 0);
195 
196     lv_obj_t * weekly_box = lv_demo_high_res_simple_container_create(box, true, c->sz->gap[2], LV_FLEX_ALIGN_START);
197     lv_obj_add_flag(weekly_box, LV_OBJ_FLAG_EVENT_BUBBLE);
198     lv_obj_set_width(weekly_box, LV_PCT(45));
199 
200     lv_obj_t * weekly_label = lv_label_create(weekly_box);
201     lv_label_set_text_static(weekly_label, "Weekly");
202     lv_obj_add_style(weekly_label, &c->fonts[FONT_LABEL_SM], 0);
203     lv_obj_set_style_text_color(weekly_label, lv_color_black(), 0);
204 
205     lv_obj_t * weekly_value_box = lv_demo_high_res_simple_container_create(weekly_box, false, c->sz->gap[1],
206                                                                            LV_FLEX_ALIGN_END);
207     lv_obj_add_flag(weekly_value_box, LV_OBJ_FLAG_EVENT_BUBBLE);
208 
209     lv_obj_t * weekly_value_label = lv_label_create(weekly_value_box);
210     lv_label_set_text_static(weekly_value_label, weekly_val);
211     lv_obj_add_style(weekly_value_label, &c->fonts[FONT_LABEL_LG], 0);
212     lv_obj_set_style_text_color(weekly_value_label, lv_color_black(), 0);
213     lv_obj_t * weekly_kwh_label = lv_label_create(weekly_value_box);
214     lv_label_set_text_static(weekly_kwh_label, "kWh");
215     lv_obj_add_style(weekly_kwh_label, &c->fonts[FONT_LABEL_SM], 0);
216     lv_obj_set_style_text_color(weekly_kwh_label, lv_color_black(), 0);
217     lv_obj_set_style_text_opa(weekly_kwh_label, LV_OPA_40, 0);
218 
219     return part;
220 }
221 
widget1_anim_height_range(lv_demo_high_res_ctx_t * c,int32_t * min,int32_t * max)222 static void widget1_anim_height_range(lv_demo_high_res_ctx_t * c, int32_t * min, int32_t * max)
223 {
224     *min = c->sz->smart_meter_collapsed_part_height;
225     *max = c->sz->card_long_edge - c->sz->gap[7] - c->sz->smart_meter_collapsed_part_height;
226 }
227 
widget1_open_part1_anim_cb(void * arg,int32_t val)228 static void widget1_open_part1_anim_cb(void * arg, int32_t val)
229 {
230     lv_obj_t * box = arg;
231     lv_demo_high_res_ctx_t * c = lv_obj_get_user_data(box);
232     lv_obj_t * part1 = lv_obj_get_child(box, 0);
233     lv_obj_t * part2 = lv_obj_get_child(box, 1);
234     int32_t min;
235     int32_t max;
236     widget1_anim_height_range(c, &min, &max);
237     lv_obj_set_height(part1, lv_map(val, 0, 1000, min, max));
238     lv_obj_set_style_bg_image_opa(part1, lv_map(val, 0, 1000, 255, 0), 0);
239     lv_obj_set_style_bg_image_opa(part2, lv_map(val, 0, 1000, 0, 255), 0);
240     lv_obj_set_style_opa(lv_obj_get_child(part1, 1), lv_map(val, 0, 1000, 0, 255), 0);
241     lv_obj_set_style_opa(lv_obj_get_child(part2, 1), lv_map(val, 0, 1000, 255, 0), 0);
242     const lv_demo_high_res_theme_t * th = lv_subject_get_pointer(&c->th);
243     if(th == &lv_demo_high_res_theme_dark) {
244         int32_t g = lv_map(val, 0, 1000, 0, 255);
245         int32_t ginv = 255 - g;
246         lv_obj_set_style_text_color(lv_obj_get_child(part1, 0), th == &lv_demo_high_res_theme_light
247                                     ? lv_color_make(g, g, g) : lv_color_make(ginv, ginv, ginv), 0);
248         lv_obj_set_style_text_color(lv_obj_get_child(part2, 0), th == &lv_demo_high_res_theme_light
249                                     ? lv_color_make(ginv, ginv, ginv) : lv_color_make(g, g, g), 0);
250     }
251 }
252 
widget1_open_part2_anim_cb(void * arg,int32_t val)253 static void widget1_open_part2_anim_cb(void * arg, int32_t val)
254 {
255     lv_obj_t * box = arg;
256     lv_demo_high_res_ctx_t * c = lv_obj_get_user_data(box);
257     lv_obj_t * part1 = lv_obj_get_child(box, 0);
258     lv_obj_t * part2 = lv_obj_get_child(box, 1);
259     int32_t min;
260     int32_t max;
261     widget1_anim_height_range(c, &min, &max);
262     lv_obj_set_height(part1, lv_map(val, 0, 1000, max, min));
263     lv_obj_set_style_bg_image_opa(part1, lv_map(val, 0, 1000, 0, 255), 0);
264     lv_obj_set_style_bg_image_opa(part2, lv_map(val, 0, 1000, 255, 0), 0);
265     lv_obj_set_style_opa(lv_obj_get_child(part1, 1), lv_map(val, 0, 1000, 255, 0), 0);
266     lv_obj_set_style_opa(lv_obj_get_child(part2, 1), lv_map(val, 0, 1000, 0, 255), 0);
267     const lv_demo_high_res_theme_t * th = lv_subject_get_pointer(&c->th);
268     if(th == &lv_demo_high_res_theme_dark) {
269         int32_t g = lv_map(val, 0, 1000, 0, 255);
270         int32_t ginv = 255 - g;
271         lv_obj_set_style_text_color(lv_obj_get_child(part1, 0), th == &lv_demo_high_res_theme_light
272                                     ? lv_color_make(ginv, ginv, ginv) : lv_color_make(g, g, g), 0);
273         lv_obj_set_style_text_color(lv_obj_get_child(part2, 0), th == &lv_demo_high_res_theme_light
274                                     ? lv_color_make(g, g, g) : lv_color_make(ginv, ginv, ginv), 0);
275     }
276 }
277 
widget1_clicked_cb(lv_event_t * e)278 static void widget1_clicked_cb(lv_event_t * e)
279 {
280     lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e);
281     lv_obj_t * part = lv_event_get_current_target_obj(e);
282     lv_obj_t * box = lv_obj_get_parent(part);
283     lv_obj_t * part1 = lv_obj_get_child(box, 0);
284     bool open_part1 = part == part1;
285 
286     if(lv_anim_get(box, NULL)) {
287         return;
288     }
289     int32_t part1_height = lv_obj_get_height(part1);
290     if((open_part1 && part1_height != c->sz->smart_meter_collapsed_part_height)
291        || (!open_part1 && part1_height == c->sz->smart_meter_collapsed_part_height)) {
292         return;
293     }
294 
295     lv_anim_t a;
296     lv_anim_init(&a);
297     lv_anim_set_duration(&a, 325);
298     lv_anim_set_exec_cb(&a, open_part1 ? widget1_open_part1_anim_cb : widget1_open_part2_anim_cb);
299     lv_anim_set_values(&a, 0, 1000);
300     lv_anim_set_var(&a, box);
301     lv_anim_start(&a);
302 }
303 
create_widget1(lv_demo_high_res_ctx_t * c,lv_obj_t * widgets)304 static void create_widget1(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets)
305 {
306     lv_obj_t * box = lv_obj_create(widgets);
307     lv_obj_remove_style_all(box);
308     lv_obj_set_size(box, c->sz->card_long_edge, c->sz->card_long_edge);
309     lv_obj_set_flex_flow(box, LV_FLEX_FLOW_COLUMN);
310     lv_obj_set_style_pad_row(box, c->sz->gap[7], 0);
311     lv_obj_set_user_data(box, c);
312 
313     lv_obj_t * part_title;
314 
315     lv_obj_t * part1 = create_widget1_part(c, box, "Self-consumption", "14.71", "89.32");
316     lv_obj_set_height(part1, c->sz->smart_meter_collapsed_part_height);
317     lv_obj_set_style_opa(lv_obj_get_child(part1, 1), LV_OPA_TRANSP, 0);
318     part_title = lv_obj_get_child(part1, 0);
319     const lv_demo_high_res_theme_t * th = lv_subject_get_pointer(&c->th);
320     lv_obj_set_style_text_color(part_title, th == &lv_demo_high_res_theme_light ? lv_color_black() : lv_color_white(), 0);
321 
322     lv_obj_t * part2 = create_widget1_part(c, box, "Production", "12.56", "90.28");
323     lv_obj_set_flex_grow(part2, 1);
324     lv_obj_set_style_bg_image_opa(part2, LV_OPA_TRANSP, 0);
325     part_title = lv_obj_get_child(part2, 0);
326     lv_obj_set_style_text_color(part_title, lv_color_black(), 0);
327 
328     lv_obj_add_event_cb(part1, widget1_clicked_cb, LV_EVENT_CLICKED, c);
329     lv_obj_add_event_cb(part2, widget1_clicked_cb, LV_EVENT_CLICKED, c);
330 }
331 
widget23_chart_label(lv_demo_high_res_ctx_t * c,lv_obj_t * parent,const char * text)332 static lv_obj_t * widget23_chart_label(lv_demo_high_res_ctx_t * c, lv_obj_t * parent, const char * text)
333 {
334     lv_obj_t * label = lv_label_create(parent);
335     lv_label_set_text_static(label, text);
336     lv_obj_add_style(label, &c->fonts[FONT_LABEL_XS], 0);
337     lv_obj_add_style(label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
338     lv_obj_set_style_text_opa(label, LV_OPA_40, 0);
339     return label;
340 }
341 
widget2_chart_event_draw_task_cb(lv_event_t * e)342 static void widget2_chart_event_draw_task_cb(lv_event_t * e)
343 {
344     lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e);
345     uint32_t idx = lv_subject_get_int(&c->smart_meter_selected_bar);
346     lv_draw_task_t * t = lv_event_get_draw_task(e);
347     lv_draw_task_type_t type = lv_draw_task_get_type(t);
348     if(type != LV_DRAW_TASK_TYPE_FILL) {
349         return;
350     }
351     lv_draw_dsc_base_t * base_draw_dsc = lv_draw_task_get_draw_dsc(t);
352     lv_obj_t * obj = lv_event_get_target_obj(e);
353     if(base_draw_dsc->part == LV_PART_MAIN) {
354         lv_draw_rect_dsc_t rect_draw_dsc;
355         lv_draw_rect_dsc_init(&rect_draw_dsc);
356         rect_draw_dsc.bg_color = lv_subject_get_pointer(&c->th) == &lv_demo_high_res_theme_light ? lv_color_black() :
357                                  lv_color_white();
358         rect_draw_dsc.bg_opa = 16 * 255 / 100;
359 
360         lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
361         lv_point_t col_pos;
362         lv_chart_get_point_pos_by_id(obj, ser, idx, &col_pos);
363 
364         int32_t w = lv_obj_get_content_width(obj) / lv_chart_get_point_count(obj);
365 
366         lv_area_t a;
367         a.x1 = obj->coords.x1 + col_pos.x - w / 2;
368         a.x2 = obj->coords.x1 + col_pos.x + w / 2;
369         a.y1 = obj->coords.y1;
370         a.y2 = obj->coords.y2;
371 
372         lv_draw_rect(base_draw_dsc->layer, &rect_draw_dsc, &a);
373     }
374     else if(base_draw_dsc->part == LV_PART_ITEMS) {
375         lv_draw_fill_dsc_t * fill_dsc = lv_draw_task_get_fill_dsc(t);
376         if(fill_dsc->base.id2 != idx) {
377             fill_dsc->opa = LV_OPA_40;
378         }
379     }
380 }
381 
widget2_chart_bar_clicked_cb(lv_event_t * e)382 static void widget2_chart_bar_clicked_cb(lv_event_t * e)
383 {
384     lv_obj_t * chart = lv_event_get_target_obj(e);
385     lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e);
386     uint32_t clicked_bar = lv_chart_get_pressed_point(chart);
387 
388     lv_subject_set_int(&c->smart_meter_selected_bar, clicked_bar);
389 }
390 
widget2_chart_selected_day_observer_cb(lv_observer_t * observer,lv_subject_t * subject)391 static void widget2_chart_selected_day_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
392 {
393     LV_UNUSED(subject);
394     lv_obj_t * chart = lv_observer_get_target_obj(observer);
395     lv_obj_invalidate(chart);
396 }
397 
create_widget2(lv_demo_high_res_ctx_t * c,lv_obj_t * widgets)398 static void create_widget2(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets)
399 {
400     lv_obj_t * widget = lv_obj_create(widgets);
401     lv_obj_remove_style_all(widget);
402     lv_obj_set_size(widget, c->sz->card_long_edge, c->sz->card_long_edge);
403     lv_subject_add_observer_obj(&c->th, lv_demo_high_res_theme_observer_obj_bg_image_src_cb, widget,
404                                 &c->imgs[IMG_LIGHT_WIDGET1_BG]);
405     lv_obj_set_style_pad_all(widget, c->sz->gap[7], 0);
406     lv_obj_set_flex_flow(widget, LV_FLEX_FLOW_COLUMN);
407     lv_obj_set_flex_align(widget, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
408     lv_obj_set_style_pad_row(widget, 18, 0);
409 
410     lv_obj_t * title_label = lv_label_create(widget);
411     lv_label_set_text_static(title_label, "Daily usage");
412     lv_obj_add_style(title_label, &c->fonts[FONT_LABEL_MD], 0);
413     lv_obj_add_style(title_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
414 
415     lv_obj_t * usage_box = lv_demo_high_res_simple_container_create(widget, true, c->sz->gap[2], LV_FLEX_ALIGN_START);
416 
417     lv_obj_t * date_label = lv_label_create(usage_box);
418     lv_label_set_text_static(date_label, "August 30, 2024");
419     lv_obj_add_style(date_label, &c->fonts[FONT_LABEL_SM], 0);
420     lv_obj_add_style(date_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
421 
422     lv_obj_t * amount_box = lv_demo_high_res_simple_container_create(usage_box, false, c->sz->gap[1], LV_FLEX_ALIGN_END);
423 
424     lv_obj_t * amount_number = lv_label_create(amount_box);
425     lv_label_set_text_static(amount_number, "15");
426     lv_obj_add_style(amount_number, &c->fonts[FONT_LABEL_XL], 0);
427     lv_obj_add_style(amount_number, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
428 
429     lv_obj_t * amount_kwh = lv_label_create(amount_box);
430     lv_label_set_text_static(amount_kwh, "kWh");
431     lv_obj_add_style(amount_kwh, &c->fonts[FONT_LABEL_SM], 0);
432     lv_obj_add_style(amount_kwh, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
433     lv_obj_set_style_text_opa(amount_kwh, LV_OPA_40, 0);
434 
435     lv_obj_t * chart_grid = lv_obj_create(widget);
436     lv_obj_remove_style_all(chart_grid);
437     lv_obj_set_size(chart_grid, LV_PCT(100), LV_SIZE_CONTENT);
438     static const int32_t column_dsc[] = {LV_GRID_FR(1), LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
439     static const int32_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
440     lv_obj_set_style_grid_column_dsc_array(chart_grid, column_dsc, 0);
441     lv_obj_set_style_grid_row_dsc_array(chart_grid, row_dsc, 0);
442     lv_obj_set_layout(chart_grid, LV_LAYOUT_GRID);
443     lv_obj_set_style_pad_column(chart_grid, c->sz->gap[3], 0);
444     lv_obj_set_style_pad_row(chart_grid, 5, 0);
445 
446     lv_obj_t * chart = lv_chart_create(chart_grid);
447     lv_obj_set_height(chart, c->sz->small_chart_height);
448     lv_obj_set_style_bg_opa(chart, LV_OPA_MIN + 1, 0);
449     lv_obj_set_style_pad_column(chart, c->sz->gap[1], 0);
450     lv_obj_set_style_radius(chart, c->sz->gap[3], LV_PART_ITEMS);
451     lv_obj_set_style_border_width(chart, 2, 0);
452     lv_obj_set_style_border_color(chart, lv_color_black(), 0);
453     lv_obj_set_style_border_side(chart, LV_BORDER_SIDE_BOTTOM, 0);
454     lv_obj_set_style_border_post(chart, true, 0);
455     lv_obj_set_style_radius(chart, 0, 0);
456     lv_obj_set_style_pad_all(chart, 0, 0);
457 
458     lv_obj_add_event_cb(chart, widget2_chart_event_draw_task_cb, LV_EVENT_DRAW_TASK_ADDED, c);
459     lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
460 
461     lv_obj_set_grid_cell(chart, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_START, 0, 1);
462     lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
463     lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 101);
464     lv_chart_set_div_line_count(chart, 3, 0);
465     lv_obj_set_style_line_opa(chart, LV_OPA_40, 0);
466     lv_obj_set_style_line_color(chart, lv_color_black(), 0);
467     lv_obj_set_style_line_dash_width(chart, 2, 0);
468     lv_obj_set_style_line_dash_gap(chart, 1, 0);
469     lv_chart_series_t * ser = lv_chart_add_series(chart, lv_color_white(), LV_CHART_AXIS_PRIMARY_Y);
470     static const int32_t chart_values[] = {45, 14, 45, 52, 69, 52, 63};
471     lv_chart_set_ext_y_array(chart, ser, (int32_t *)chart_values);
472     lv_chart_set_point_count(chart, sizeof(chart_values) / sizeof(*chart_values));
473     lv_chart_refresh(chart);
474 
475     lv_obj_add_event_cb(chart, widget2_chart_bar_clicked_cb, LV_EVENT_VALUE_CHANGED, c);
476     lv_subject_add_observer_obj(&c->smart_meter_selected_bar, widget2_chart_selected_day_observer_cb, chart, NULL);
477 
478     lv_obj_t * hscale_label_1 = widget23_chart_label(c, chart_grid, "Aug 2");
479     lv_obj_set_grid_cell(hscale_label_1, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 1, 1);
480     lv_obj_t * hscale_label_2 = widget23_chart_label(c, chart_grid, "Sep 1");
481     lv_obj_set_grid_cell(hscale_label_2, LV_GRID_ALIGN_END, 0, 1, LV_GRID_ALIGN_START, 1, 1);
482 
483     lv_obj_t * vscale_label_1 = widget23_chart_label(c, chart_grid, "20");
484     lv_obj_set_grid_cell(vscale_label_1, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_START, 0, 1);
485     lv_obj_t * vscale_label_2 = widget23_chart_label(c, chart_grid, "10");
486     lv_obj_set_grid_cell(vscale_label_2, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
487     lv_obj_t * vscale_label_3 = widget23_chart_label(c, chart_grid, "0");
488     lv_obj_set_grid_cell(vscale_label_3, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_END, 0, 1);
489 }
490 
widget3_chart_draw_task_event_cb(lv_event_t * e)491 static void widget3_chart_draw_task_event_cb(lv_event_t * e)
492 {
493     lv_draw_task_t * t = lv_event_get_draw_task(e);
494     lv_draw_task_type_t task_type = lv_draw_task_get_type(t);
495 
496     if(task_type == LV_DRAW_TASK_TYPE_FILL) {
497         lv_draw_dsc_base_t * base_draw_dsc = lv_draw_task_get_draw_dsc(t);
498         if(base_draw_dsc->part != LV_PART_ITEMS) return;
499 
500         lv_obj_t * obj = lv_event_get_target(e);
501         lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
502         int32_t * ser_array = ser->y_points;
503         int32_t p_idx = base_draw_dsc->id2;
504         int32_t v = ser_array[p_idx];
505         int32_t mid_y = obj->coords.y1 + lv_obj_get_height(obj) / 2;
506         if(v < 0) {
507             t->area.y2 = t->area.y1;
508             t->area.y1 = mid_y;
509         }
510         else {
511             t->area.y2 = mid_y;
512         }
513     }
514     else if(task_type == LV_DRAW_TASK_TYPE_LINE) {
515         lv_draw_line_dsc_t * line_draw_dsc = lv_draw_task_get_draw_dsc(t);
516         if(line_draw_dsc->base.id1 != 1) return;
517         line_draw_dsc->dash_gap = 0;
518         line_draw_dsc->color = lv_color_black();
519         line_draw_dsc->opa = LV_OPA_COVER;
520         line_draw_dsc->width = 2;
521         line_draw_dsc->p1.y -= 1;
522         line_draw_dsc->p2.y -= 1;
523     }
524 }
525 
widget3_chart_free_anim_values(lv_event_t * e)526 static void widget3_chart_free_anim_values(lv_event_t * e)
527 {
528     lv_obj_t * chart = lv_event_get_target_obj(e);
529     widget3_chart_anim_values_t * anim_values = lv_obj_get_user_data(chart);
530     lv_free(anim_values);
531 }
532 
widget3_chart_anim_cb(void * var,int32_t v)533 static void widget3_chart_anim_cb(void * var, int32_t v)
534 {
535     lv_obj_t * chart = var;
536     widget3_chart_anim_values_t * anim_values = lv_obj_get_user_data(chart);
537     int32_t * end_values = lv_anim_get_user_data(lv_anim_get(var, widget3_chart_anim_cb));
538 
539     for(int32_t i = 0; i < WIDGET3_POINT_COUNT; i++) {
540         anim_values->current[i] = lv_map(v, 0, WIDGET3_ANIM_RANGE_END, anim_values->start[i], end_values[i]);
541     }
542 
543     lv_chart_refresh(chart);
544 }
545 
widget3_chart_selected_day_observer_cb(lv_observer_t * observer,lv_subject_t * subject)546 static void widget3_chart_selected_day_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
547 {
548     static bool data_is_init = false;
549     static int32_t data[WIDGET3_POINT_COUNT * 7];
550     if(!data_is_init) {
551         data_is_init = true;
552         for(int32_t i = 0; i < WIDGET3_POINT_COUNT * 7; i++) {
553             data[i] = lv_map(-lv_trigo_cos(i * 15), -32767, 32767, -105, 105) + lv_rand(-20, 20);
554         }
555     }
556 
557     lv_obj_t * chart = lv_observer_get_target_obj(observer);
558     int32_t idx = lv_subject_get_int(subject);
559 
560     widget3_chart_anim_values_t * anim_values = lv_obj_get_user_data(chart);
561     if(!anim_values) {
562         anim_values = lv_malloc_zeroed(sizeof(widget3_chart_anim_values_t));
563         LV_ASSERT_MALLOC(anim_values);
564         lv_obj_set_user_data(chart, anim_values);
565         lv_obj_add_event_cb(chart, widget3_chart_free_anim_values, LV_EVENT_DELETE, NULL);
566 
567         lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);
568         lv_chart_set_ext_y_array(chart, ser, anim_values->current);
569     }
570 
571     lv_memcpy(anim_values->start, anim_values->current, sizeof(anim_values->current));
572 
573     lv_anim_t a;
574     lv_anim_init(&a);
575     lv_anim_set_var(&a, chart);
576     lv_anim_set_duration(&a, 400);
577     lv_anim_set_values(&a, 0, WIDGET3_ANIM_RANGE_END);
578     lv_anim_set_exec_cb(&a, widget3_chart_anim_cb);
579     lv_anim_set_user_data(&a, &data[idx * WIDGET3_POINT_COUNT]);
580     lv_anim_set_early_apply(&a, true);
581     lv_anim_start(&a);
582 }
583 
create_widget3_stat(lv_demo_high_res_ctx_t * c,lv_obj_t * parent,const char * title_val,const char * kwh_val,const char * detail_val)584 static lv_obj_t * create_widget3_stat(lv_demo_high_res_ctx_t * c, lv_obj_t * parent, const char * title_val,
585                                       const char * kwh_val, const char * detail_val)
586 {
587     lv_obj_t * obj = lv_demo_high_res_simple_container_create(parent, true, c->sz->gap[4], LV_FLEX_ALIGN_START);
588     lv_obj_set_flex_grow(obj, 1);
589 
590     lv_obj_t * title_label = lv_label_create(obj);
591     lv_label_set_text_static(title_label, title_val);
592     lv_obj_add_style(title_label, &c->fonts[FONT_LABEL_SM], 0);
593     lv_obj_add_style(title_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
594 
595     lv_obj_t * kwh_box = lv_demo_high_res_simple_container_create(obj, false, c->sz->gap[1], LV_FLEX_ALIGN_END);
596 
597     lv_obj_t * kwh_value_label = lv_label_create(kwh_box);
598     lv_label_set_text_static(kwh_value_label, kwh_val);
599     lv_obj_add_style(kwh_value_label, &c->fonts[FONT_LABEL_XL], 0);
600     lv_obj_add_style(kwh_value_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
601 
602     lv_obj_t * kwh_label = lv_label_create(kwh_box);
603     lv_label_set_text_static(kwh_label, "kWh");
604     lv_obj_add_style(kwh_label, &c->fonts[FONT_LABEL_SM], 0);
605     lv_obj_add_style(kwh_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
606     lv_obj_set_style_text_opa(kwh_label, LV_OPA_60, 0);
607 
608     lv_obj_t * detail_label = lv_label_create(obj);
609     lv_label_set_text_static(detail_label, detail_val);
610     lv_obj_add_style(detail_label, &c->fonts[FONT_LABEL_SM], 0);
611     lv_obj_add_style(detail_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
612     lv_obj_set_style_text_opa(detail_label, LV_OPA_60, 0);
613 
614     return obj;
615 }
616 
create_widget3(lv_demo_high_res_ctx_t * c,lv_obj_t * widgets)617 static void create_widget3(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets)
618 {
619     lv_obj_t * widget = lv_obj_create(widgets);
620     lv_obj_remove_style_all(widget);
621     lv_obj_set_size(widget, c->imgs[IMG_LIGHT_WIDGET5_BG]->header.w, c->imgs[IMG_LIGHT_WIDGET5_BG]->header.h);
622     lv_subject_add_observer_obj(&c->th, lv_demo_high_res_theme_observer_obj_bg_image_src_cb, widget,
623                                 &c->imgs[IMG_LIGHT_WIDGET5_BG]);
624     lv_obj_set_style_pad_all(widget, c->sz->gap[7], 0);
625     lv_obj_set_flex_flow(widget, LV_FLEX_FLOW_COLUMN);
626     lv_obj_set_flex_align(widget, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
627 
628     lv_obj_t * title_label = lv_label_create(widget);
629     lv_label_set_text_static(title_label, "Balance");
630     lv_obj_add_style(title_label, &c->fonts[FONT_LABEL_MD], 0);
631     lv_obj_add_style(title_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
632 
633     lv_obj_t * chart_grid = lv_obj_create(widget);
634     lv_obj_remove_style_all(chart_grid);
635     lv_obj_set_size(chart_grid, LV_PCT(100), LV_SIZE_CONTENT);
636     static const int32_t column_dsc[] = {LV_GRID_FR(1), LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
637     static const int32_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
638     lv_obj_set_style_grid_column_dsc_array(chart_grid, column_dsc, 0);
639     lv_obj_set_style_grid_row_dsc_array(chart_grid, row_dsc, 0);
640     lv_obj_set_layout(chart_grid, LV_LAYOUT_GRID);
641     lv_obj_set_style_pad_column(chart_grid, c->sz->gap[3], 0);
642     lv_obj_set_style_pad_row(chart_grid, 5, 0);
643 
644     lv_obj_t * chart = lv_chart_create(chart_grid);
645     lv_obj_set_height(chart, c->sz->large_chart_height);
646     lv_obj_set_style_bg_opa(chart, LV_OPA_TRANSP, 0);
647     lv_obj_set_style_pad_column(chart, c->sz->gap[1], 0);
648     lv_obj_set_style_radius(chart, c->sz->gap[3], LV_PART_ITEMS);
649     lv_obj_set_style_border_side(chart, LV_BORDER_SIDE_NONE, 0);
650     lv_obj_set_style_radius(chart, 0, 0);
651     lv_obj_set_style_pad_all(chart, 5, 0);
652     lv_obj_set_grid_cell(chart, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_START, 0, 1);
653     lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
654     lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -125, 125);
655     lv_chart_set_div_line_count(chart, 3, 0);
656     lv_obj_set_style_line_opa(chart, LV_OPA_40, 0);
657     lv_obj_set_style_line_color(chart, lv_color_black(), 0);
658     lv_obj_set_style_line_dash_width(chart, 2, 0);
659     lv_obj_set_style_line_dash_gap(chart, 1, 0);
660     lv_obj_add_event_cb(chart, widget3_chart_draw_task_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
661     lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
662     lv_chart_add_series(chart, lv_color_white(), LV_CHART_AXIS_PRIMARY_Y);
663     lv_chart_set_point_count(chart, WIDGET3_POINT_COUNT);
664     lv_subject_add_observer_obj(&c->smart_meter_selected_bar, widget3_chart_selected_day_observer_cb, chart, NULL);
665 
666     lv_obj_t * hscale_label_1 = widget23_chart_label(c, chart_grid, "0h");
667     lv_obj_set_grid_cell(hscale_label_1, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 1, 1);
668     lv_obj_t * hscale_label_2 = widget23_chart_label(c, chart_grid, "24h");
669     lv_obj_set_grid_cell(hscale_label_2, LV_GRID_ALIGN_END, 0, 1, LV_GRID_ALIGN_START, 1, 1);
670 
671     lv_obj_t * vscale_label_1 = widget23_chart_label(c, chart_grid, "5");
672     lv_obj_set_grid_cell(vscale_label_1, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_START, 0, 1);
673     lv_obj_t * vscale_label_2 = widget23_chart_label(c, chart_grid, "0\nkWh");
674     lv_obj_set_grid_cell(vscale_label_2, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
675     lv_obj_t * vscale_label_3 = widget23_chart_label(c, chart_grid, "-5");
676     lv_obj_set_grid_cell(vscale_label_3, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_END, 0, 1);
677 
678     lv_obj_t * stat_box = lv_demo_high_res_simple_container_create(widget, false, c->sz->gap[5], LV_FLEX_ALIGN_CENTER);
679     lv_obj_set_width(stat_box, LV_PCT(100));
680     create_widget3_stat(c, stat_box, "Sep 1, 2024", "+12", "P:  +36kWh U: -18kWh");
681     create_widget3_stat(c, stat_box, "Week 41", "-56", "P:  +243kWh U: -299kWh");
682 }
683 
684 #endif /*LV_USE_DEMO_HIGH_RES*/
685