1313#include " esp_chip_info.h"
1414
1515static lv_obj_t *screen_main;
16+ static lv_obj_t *msg_list;
17+ static lv_obj_t *kb;
1618static lv_obj_t *mem_label;
17- static lv_obj_t *chip_label;
1819static lv_obj_t *chart;
1920static lv_chart_series_t * ser;
21+ static lv_obj_t * arc_thermo;
22+ static lv_obj_t * label_thermo;
2023static int tick_count = 0 ;
2124
25+ static void add_chat_bubble (const char * txt, bool is_user) {
26+ lv_obj_t * wrapper = lv_obj_create (msg_list);
27+ lv_obj_set_width (wrapper, lv_pct (100 ));
28+ lv_obj_set_height (wrapper, LV_SIZE_CONTENT);
29+ lv_obj_set_style_bg_opa (wrapper, 0 , 0 );
30+ lv_obj_set_style_border_width (wrapper, 0 , 0 );
31+ lv_obj_set_style_pad_all (wrapper, 0 , 0 );
32+ lv_obj_clear_flag (wrapper, LV_OBJ_FLAG_SCROLLABLE);
33+
34+ lv_obj_t * msg_box = lv_obj_create (wrapper);
35+ lv_obj_set_size (msg_box, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
36+ lv_obj_set_style_radius (msg_box, 15 , 0 );
37+ lv_obj_set_style_border_width (msg_box, 0 , 0 );
38+ lv_obj_set_style_pad_all (msg_box, 15 , 0 );
39+
40+ lv_obj_t * label = lv_label_create (msg_box);
41+ lv_label_set_text (label, txt);
42+ lv_label_set_long_mode (label, LV_LABEL_LONG_WRAP);
43+ lv_obj_set_width (label, 300 ); // fixed max width for wrap
44+
45+ if (is_user) {
46+ lv_obj_set_style_bg_color (msg_box, lv_color_hex (0x2196F3 ), 0 );
47+ lv_obj_set_style_text_color (label, lv_color_hex (0xFFFFFF ), 0 );
48+ lv_obj_align (msg_box, LV_ALIGN_RIGHT_MID, -10 , 0 );
49+ } else {
50+ lv_obj_set_style_bg_color (msg_box, lv_color_hex (0xE0E0E0 ), 0 );
51+ lv_obj_set_style_text_color (label, lv_color_hex (0x333333 ), 0 );
52+ lv_obj_align (msg_box, LV_ALIGN_LEFT_MID, 10 , 0 );
53+ }
54+ lv_obj_scroll_to_view (wrapper, LV_ANIM_ON);
55+ }
56+
57+ static void ta_event_cb (lv_event_t * e) {
58+ lv_event_code_t code = lv_event_get_code (e);
59+ lv_obj_t * ta = lv_event_get_target (e);
60+ if (code == LV_EVENT_FOCUSED) {
61+ lv_keyboard_set_textarea (kb, ta);
62+ lv_obj_clear_flag (kb, LV_OBJ_FLAG_HIDDEN);
63+ lv_obj_move_foreground (kb);
64+ } else if (code == LV_EVENT_DEFOCUSED) {
65+ lv_obj_add_flag (kb, LV_OBJ_FLAG_HIDDEN);
66+ } else if (code == LV_EVENT_READY) {
67+ const char * txt = lv_textarea_get_text (ta);
68+ if (strlen (txt) > 0 ) {
69+ add_chat_bubble (txt, true );
70+ // Simulate bot reply
71+ add_chat_bubble (" I am a demo bot! That's interesting." , false );
72+ }
73+ lv_textarea_set_text (ta, " " );
74+ lv_obj_add_flag (kb, LV_OBJ_FLAG_HIDDEN);
75+ lv_obj_clear_state (ta, LV_STATE_FOCUSED);
76+ }
77+ }
78+
79+ static void thermo_anim_cb (void * var, int32_t v) {
80+ lv_arc_set_value ((lv_obj_t *)var, v);
81+ char buf[16 ];
82+ snprintf (buf, sizeof (buf), " %d\xc2\xb0 " " C" , (int )v); // UTF-8 degree symbol
83+ lv_label_set_text (label_thermo, buf);
84+ }
85+
2286static void gui_build_main_screen () {
2387 screen_main = lv_obj_create (NULL );
24- // White background
25- lv_obj_set_style_bg_color (screen_main, lv_color_hex (0xFFFFFF ), LV_PART_MAIN);
88+ lv_obj_set_style_bg_color (screen_main, lv_color_hex (0xF5F7FA ), LV_PART_MAIN);
2689
27- // Create a tab view
28- lv_obj_t * tabview = lv_tabview_create (screen_main, LV_DIR_TOP, 50 );
29- lv_obj_set_style_bg_color (tabview, lv_color_hex (0xFFFFFF ), LV_PART_MAIN);
90+ // Left sidebar tab view for landscape Pro look
91+ lv_obj_t * tabview = lv_tabview_create (screen_main, LV_DIR_LEFT, 100 );
92+ lv_obj_set_style_bg_color (tabview, lv_color_hex (0xF5F7FA ), LV_PART_MAIN);
3093
31- // Get the buttons part of the tabview and style it
3294 lv_obj_t * tab_btns = lv_tabview_get_tab_btns (tabview);
33- lv_obj_set_style_bg_color (tab_btns, lv_color_hex (0xF0F0F0 ), LV_PART_MAIN);
34- lv_obj_set_style_text_color (tab_btns, lv_color_hex (0x999999 ), LV_PART_MAIN);
95+ lv_obj_set_style_bg_color (tab_btns, lv_color_hex (0xFFFFFF ), LV_PART_MAIN);
96+ lv_obj_set_style_text_color (tab_btns, lv_color_hex (0x888888 ), LV_PART_MAIN);
3597 lv_obj_set_style_text_color (tab_btns, lv_color_hex (0x2196F3 ), (lv_style_selector_t )((int )LV_PART_ITEMS | (int )LV_STATE_CHECKED));
98+ lv_obj_set_style_border_width (tab_btns, 0 , LV_PART_MAIN);
99+ lv_obj_set_style_shadow_width (tab_btns, 15 , LV_PART_MAIN);
100+ lv_obj_set_style_shadow_color (tab_btns, lv_color_hex (0x000000 ), LV_PART_MAIN);
101+ lv_obj_set_style_shadow_opa (tab_btns, 15 , LV_PART_MAIN);
102+
103+ lv_obj_t * tab1 = lv_tabview_add_tab (tabview, " \n " LV_SYMBOL_HOME " \n Home" );
104+ lv_obj_t * tab2 = lv_tabview_add_tab (tabview, " \n " LV_SYMBOL_SETTINGS " \n Ctrl" );
105+ lv_obj_t * tab3 = lv_tabview_add_tab (tabview, " \n " LV_SYMBOL_BELL " \n Chat" );
106+
107+ // --- TAB 1: Home Dashboard ---
108+ lv_obj_set_layout (tab1, LV_LAYOUT_FLEX);
109+ lv_obj_set_flex_flow (tab1, LV_FLEX_FLOW_ROW_WRAP);
110+ lv_obj_set_flex_align (tab1, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
111+ lv_obj_set_style_pad_all (tab1, 20 , 0 );
112+
113+ // Card 1: Thermostat
114+ lv_obj_t * card1 = lv_obj_create (tab1);
115+ lv_obj_set_size (card1, 280 , 280 );
116+ lv_obj_set_style_radius (card1, 20 , 0 );
117+ lv_obj_set_style_border_width (card1, 0 , 0 );
118+ lv_obj_set_style_shadow_width (card1, 20 , 0 );
119+ lv_obj_set_style_shadow_color (card1, lv_color_hex (0x000000 ), 0 );
120+ lv_obj_set_style_shadow_opa (card1, 10 , 0 );
121+
122+ lv_obj_t * thermo_title = lv_label_create (card1);
123+ lv_label_set_text (thermo_title, " Living Room" );
124+ lv_obj_align (thermo_title, LV_ALIGN_TOP_MID, 0 , 0 );
125+ lv_obj_set_style_text_color (thermo_title, lv_color_hex (0x888888 ), 0 );
126+
127+ arc_thermo = lv_arc_create (card1);
128+ lv_obj_set_size (arc_thermo, 180 , 180 );
129+ lv_obj_align (arc_thermo, LV_ALIGN_CENTER, 0 , 15 );
130+ lv_arc_set_range (arc_thermo, 10 , 35 );
131+ lv_arc_set_value (arc_thermo, 10 );
132+ lv_obj_set_style_arc_color (arc_thermo, lv_color_hex (0xE0E0E0 ), LV_PART_MAIN);
133+ lv_obj_set_style_arc_color (arc_thermo, lv_color_hex (0xFF9800 ), LV_PART_INDICATOR);
134+ lv_obj_set_style_arc_width (arc_thermo, 15 , LV_PART_MAIN);
135+ lv_obj_set_style_arc_width (arc_thermo, 15 , LV_PART_INDICATOR);
136+ lv_obj_remove_style (arc_thermo, NULL , LV_PART_KNOB);
137+
138+ label_thermo = lv_label_create (card1);
139+ lv_label_set_text (label_thermo, " 10\xc2\xb0 " " C" );
140+ lv_obj_align (label_thermo, LV_ALIGN_CENTER, 0 , 15 );
141+ // Note: ensure font supports degree symbol, otherwise it may not show. We use default font.
36142
37- // Add 3 tabs
38- lv_obj_t * tab1 = lv_tabview_add_tab (tabview, " Controls" );
39- lv_obj_t * tab2 = lv_tabview_add_tab (tabview, " Dashboard" );
40- lv_obj_t * tab3 = lv_tabview_add_tab (tabview, " System" );
41-
42- // --- TAB 1: Controls ---
43- // A slider
44- lv_obj_t * slider = lv_slider_create (tab1);
45- lv_obj_align (slider, LV_ALIGN_TOP_MID, 0 , 20 );
46- lv_obj_set_width (slider, 200 );
47- lv_obj_set_style_bg_color (slider, lv_color_hex (0xDDDDDD ), LV_PART_MAIN);
48- lv_obj_set_style_bg_color (slider, lv_color_hex (0x2196F3 ), LV_PART_INDICATOR);
49-
50- // A switch
51- lv_obj_t * sw = lv_switch_create (tab1);
52- lv_obj_align (sw, LV_ALIGN_CENTER, -60 , 20 );
53- lv_obj_set_style_bg_color (sw, lv_color_hex (0x4CAF50 ), (lv_style_selector_t )((int )LV_PART_INDICATOR | (int )LV_STATE_CHECKED));
54-
55- // An arc
56- lv_obj_t * arc = lv_arc_create (tab1);
57- lv_obj_set_size (arc, 100 , 100 );
58- lv_obj_align (arc, LV_ALIGN_CENTER, 60 , 20 );
59- lv_arc_set_value (arc, 40 );
60- lv_obj_set_style_arc_color (arc, lv_color_hex (0xDDDDDD ), LV_PART_MAIN);
61- lv_obj_set_style_arc_color (arc, lv_color_hex (0x2196F3 ), LV_PART_INDICATOR);
62-
63- // --- TAB 2: Dashboard ---
64- chart = lv_chart_create (tab2);
65- lv_obj_set_size (chart, 240 , 150 );
66- lv_obj_align (chart, LV_ALIGN_CENTER, 0 , 0 );
143+ // Card 2: Power Chart
144+ lv_obj_t * card2 = lv_obj_create (tab1);
145+ lv_obj_set_size (card2, 340 , 280 );
146+ lv_obj_set_style_radius (card2, 20 , 0 );
147+ lv_obj_set_style_border_width (card2, 0 , 0 );
148+ lv_obj_set_style_shadow_width (card2, 20 , 0 );
149+ lv_obj_set_style_shadow_color (card2, lv_color_hex (0x000000 ), 0 );
150+ lv_obj_set_style_shadow_opa (card2, 10 , 0 );
151+
152+ lv_obj_t * chart_title = lv_label_create (card2);
153+ lv_label_set_text (chart_title, " Power Usage (W)" );
154+ lv_obj_align (chart_title, LV_ALIGN_TOP_MID, 0 , 0 );
155+ lv_obj_set_style_text_color (chart_title, lv_color_hex (0x888888 ), 0 );
156+
157+ chart = lv_chart_create (card2);
158+ lv_obj_set_size (chart, 300 , 180 );
159+ lv_obj_align (chart, LV_ALIGN_CENTER, 0 , 15 );
67160 lv_chart_set_type (chart, LV_CHART_TYPE_LINE);
68- lv_obj_set_style_bg_color (chart, lv_color_hex (0xFAFAFA ), LV_PART_MAIN);
69- lv_obj_set_style_line_color (chart, lv_color_hex (0xCCCCCC ), LV_PART_ITEMS);
161+ lv_obj_set_style_bg_opa (chart, 0 , LV_PART_MAIN);
162+ lv_obj_set_style_border_width (chart, 0 , LV_PART_MAIN);
163+ lv_obj_set_style_line_width (chart, 3 , LV_PART_ITEMS);
164+ lv_obj_set_style_line_color (chart, lv_color_hex (0x2196F3 ), LV_PART_ITEMS);
70165
71- // Add data series
72- ser = lv_chart_add_series (chart, lv_color_hex (0x009688 ), LV_CHART_AXIS_PRIMARY_Y);
166+ ser = lv_chart_add_series (chart, lv_color_hex (0x2196F3 ), LV_CHART_AXIS_PRIMARY_Y);
73167 for (int i = 0 ; i < 10 ; i++) {
74- lv_chart_set_next_value (chart, ser, lv_rand (10 , 90 ));
168+ lv_chart_set_next_value (chart, ser, lv_rand (100 , 500 ));
169+ }
170+
171+ // --- TAB 2: Controls ---
172+ lv_obj_set_layout (tab2, LV_LAYOUT_FLEX);
173+ lv_obj_set_flex_flow (tab2, LV_FLEX_FLOW_ROW_WRAP);
174+ lv_obj_set_flex_align (tab2, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
175+
176+ for (int i=0 ; i<6 ; i++) {
177+ lv_obj_t * c_card = lv_obj_create (tab2);
178+ lv_obj_set_size (c_card, 220 , 120 );
179+ lv_obj_set_style_radius (c_card, 15 , 0 );
180+ lv_obj_set_style_border_width (c_card, 0 , 0 );
181+ lv_obj_set_style_shadow_width (c_card, 10 , 0 );
182+ lv_obj_set_style_shadow_color (c_card, lv_color_hex (0x000000 ), 0 );
183+ lv_obj_set_style_shadow_opa (c_card, 10 , 0 );
184+
185+ lv_obj_t * sw = lv_switch_create (c_card);
186+ lv_obj_align (sw, LV_ALIGN_RIGHT_MID, -10 , 0 );
187+ lv_obj_set_style_bg_color (sw, lv_color_hex (0x4CAF50 ), (lv_style_selector_t )((int )LV_PART_INDICATOR | (int )LV_STATE_CHECKED));
188+
189+ lv_obj_t * l = lv_label_create (c_card);
190+ char lbuf[32 ];
191+ snprintf (lbuf, sizeof (lbuf), " Light %d" , i+1 );
192+ lv_label_set_text (l, lbuf);
193+ lv_obj_align (l, LV_ALIGN_LEFT_MID, 10 , 0 );
75194 }
76195
77- // --- TAB 3: System ---
78- mem_label = lv_label_create (tab3);
79- lv_label_set_text (mem_label, " Mem: --" );
80- lv_obj_align (mem_label, LV_ALIGN_TOP_LEFT, 10 , 10 );
81- lv_obj_set_style_text_color (mem_label, lv_color_hex (0x555555 ), LV_PART_MAIN);
82-
83- chip_label = lv_label_create (tab3);
84- esp_chip_info_t chip_info;
85- esp_chip_info (&chip_info);
86- char cbuf[128 ];
87- snprintf (cbuf, sizeof (cbuf), " Cores: %d\n Rev: %d" , chip_info.cores , chip_info.revision );
88- lv_label_set_text (chip_label, cbuf);
89- lv_obj_align (chip_label, LV_ALIGN_TOP_LEFT, 10 , 60 );
90- lv_obj_set_style_text_color (chip_label, lv_color_hex (0x555555 ), LV_PART_MAIN);
196+ // --- TAB 3: Fake Chat ---
197+ lv_obj_t * chat_container = lv_obj_create (tab3);
198+ lv_obj_set_size (chat_container, LV_PCT (100 ), LV_PCT (100 ));
199+ lv_obj_set_style_border_width (chat_container, 0 , 0 );
200+ lv_obj_set_style_bg_opa (chat_container, 0 , 0 );
201+ lv_obj_set_style_pad_all (chat_container, 0 , 0 );
202+ lv_obj_set_layout (chat_container, LV_LAYOUT_FLEX);
203+ lv_obj_set_flex_flow (chat_container, LV_FLEX_FLOW_COLUMN);
204+
205+ msg_list = lv_obj_create (chat_container);
206+ lv_obj_set_width (msg_list, LV_PCT (100 ));
207+ lv_obj_set_flex_grow (msg_list, 1 );
208+ lv_obj_set_style_border_width (msg_list, 0 , 0 );
209+ lv_obj_set_style_bg_color (msg_list, lv_color_hex (0xF5F7FA ), 0 );
210+ lv_obj_set_layout (msg_list, LV_LAYOUT_FLEX);
211+ lv_obj_set_flex_flow (msg_list, LV_FLEX_FLOW_COLUMN);
212+
213+ lv_obj_t * ta = lv_textarea_create (chat_container);
214+ lv_textarea_set_one_line (ta, true );
215+ lv_obj_set_width (ta, LV_PCT (100 ));
216+ lv_textarea_set_placeholder_text (ta, " Type a message..." );
217+ lv_obj_add_event_cb (ta, ta_event_cb, LV_EVENT_ALL, NULL );
218+
219+ // Global keyboard
220+ kb = lv_keyboard_create (screen_main);
221+ lv_obj_add_flag (kb, LV_OBJ_FLAG_HIDDEN);
222+
223+ // Setup initial chat
224+ add_chat_bubble (" Hello! I'm your smart home assistant." , false );
225+
226+ // System info in corner
227+ mem_label = lv_label_create (screen_main);
228+ lv_obj_align (mem_label, LV_ALIGN_BOTTOM_RIGHT, -10 , -10 );
229+ lv_obj_set_style_text_color (mem_label, lv_color_hex (0xAAAAAA ), 0 );
230+
231+ // Startup Animation for thermostat
232+ lv_anim_t a;
233+ lv_anim_init (&a);
234+ lv_anim_set_var (&a, arc_thermo);
235+ lv_anim_set_exec_cb (&a, thermo_anim_cb);
236+ lv_anim_set_time (&a, 1500 );
237+ lv_anim_set_values (&a, 10 , 24 );
238+ lv_anim_start (&a);
91239}
92240
93241extern " C" void DisplayDemo_Init () {
@@ -105,24 +253,15 @@ extern "C" void DisplayDemo_Init() {
105253
106254extern " C" void DisplayDemo_OnEverySecond () {
107255 if (!g_display_ready) return ;
108-
109256 tick_count++;
110257
111- char mbuf[128 ];
258+ char mbuf[64 ];
112259 size_t free_int = heap_caps_get_free_size (MALLOC_CAP_INTERNAL);
113- size_t max_int = heap_caps_get_largest_free_block (MALLOC_CAP_INTERNAL);
114- size_t free_spi = heap_caps_get_free_size (MALLOC_CAP_SPIRAM);
115- size_t max_spi = heap_caps_get_largest_free_block (MALLOC_CAP_SPIRAM);
116- snprintf (mbuf, sizeof (mbuf), " INT: %u (%u max)\n SPI: %u (%u max)" ,
117- (unsigned )free_int, (unsigned )max_int, (unsigned )free_spi, (unsigned )max_spi);
260+ snprintf (mbuf, sizeof (mbuf), " Free Mem: %u B" , (unsigned )free_int);
118261
119262 lvgl_port_lock (-1 );
120- if (mem_label) {
121- lv_label_set_text (mem_label, mbuf);
122- }
123- if (chart && ser) {
124- lv_chart_set_next_value (chart, ser, lv_rand (10 , 90 ));
125- }
263+ if (mem_label) lv_label_set_text (mem_label, mbuf);
264+ if (chart && ser) lv_chart_set_next_value (chart, ser, lv_rand (100 , 500 ));
126265 lvgl_port_unlock ();
127266}
128267
0 commit comments