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