-
Notifications
You must be signed in to change notification settings - Fork 296
Expand file tree
/
Copy pathui_setup_screen.c
More file actions
185 lines (168 loc) · 7.51 KB
/
Copy pathui_setup_screen.c
File metadata and controls
185 lines (168 loc) · 7.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "ui_setup_screen.h"
#include "../lvgl_port.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
LV_IMG_DECLARE(updown_img);
lv_obj_t *setup_screen = NULL;
lv_obj_t *channel_label = NULL;
lv_obj_t *id_label = NULL;
lv_obj_t *channel_dropdown = NULL;
lv_obj_t *id_dropdown = NULL;
/**
* @brief Create the setup screen UI with configuration options
* @note This function creates a standalone screen with multiple UI elements:
* - Title label at the top
* - Channel selection dropdown with options 1-14
* - ID selection dropdown with options 0-50
* - Start button at the bottom for transitioning to running mode
* @details The function sets up dropdown controls with initial selections and
* applies specific styling including background colors and transparency
* @warning This function should only be called once per application run to avoid memory leaks
*/
void create_setup_screen()
{
while (!lvgl_port_lock()) {
vTaskDelay(pdMS_TO_TICKS(10));
}
lv_disp_t *disp = lv_disp_get_default();
if (disp == NULL) {
ESP_LOGE("UI", "No default display found!");
lvgl_port_unlock();
return;
}
if (setup_screen == NULL) {
setup_screen = lv_obj_create(NULL);
}
lv_obj_clear_flag(setup_screen, LV_OBJ_FLAG_SCROLLABLE);
// Create title
lv_obj_t *label = lv_label_create(setup_screen);
lv_label_set_text(label, "StackChan :)");
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);
// Create Channel selection label
channel_label = lv_label_create(setup_screen);
lv_label_set_text(channel_label, "Channel:");
lv_obj_align(channel_label, LV_ALIGN_TOP_LEFT, 5, 30);
// Create Channel dropdown
channel_dropdown = lv_dropdown_create(setup_screen);
lv_dropdown_set_options(channel_dropdown, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14");
lv_dropdown_set_selected(channel_dropdown, 0);
lv_obj_align(channel_dropdown, LV_ALIGN_TOP_LEFT, 5, 50);
lv_dropdown_set_symbol(channel_dropdown, &updown_img);
// Set dropdown background color
lv_obj_set_style_bg_color(channel_dropdown, lv_color_make(255, 255, 255), LV_PART_MAIN); // White
lv_obj_set_style_bg_opa(channel_dropdown, LV_OPA_COVER, LV_PART_MAIN); // Ensure background is opaque
// Create ID selection label
id_label = lv_label_create(setup_screen);
lv_label_set_text(id_label, "Receiver ID:");
lv_obj_align(id_label, LV_ALIGN_TOP_LEFT, 5, 100);
// Create ID dropdown
id_dropdown = lv_dropdown_create(setup_screen);
lv_dropdown_set_options(
id_dropdown,
"0(Broadcast)"
"\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n3"
"0\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50");
lv_dropdown_set_selected(id_dropdown, 0);
lv_obj_align(id_dropdown, LV_ALIGN_TOP_LEFT, 5, 120);
lv_dropdown_set_symbol(id_dropdown, &updown_img);
// Set dropdown background color
lv_obj_set_style_bg_color(id_dropdown, lv_color_make(255, 255, 255), LV_PART_MAIN); // White
lv_obj_set_style_bg_opa(id_dropdown, LV_OPA_COVER, LV_PART_MAIN); // Ensure background is opaque
lv_obj_t *btn_label = lv_label_create(setup_screen);
lv_label_set_text(btn_label, "Press to Start");
lv_obj_set_style_text_font(btn_label, &lv_font_montserrat_18, 0);
lv_obj_align(btn_label, LV_ALIGN_BOTTOM_MID, 0, -30);
lv_obj_t *arrow_label = lv_label_create(setup_screen);
lv_label_set_text(arrow_label, LV_SYMBOL_DOWN);
lv_obj_align(arrow_label, LV_ALIGN_BOTTOM_MID, 0, -5);
lvgl_port_unlock();
}
/**
* @brief Update the setup screen UI based on joystick input
* @param data Pointer to joystick_data_t structure containing current joystick values and selection mode
* @note This function handles joystick input to navigate and modify settings:
* - Highlights the currently selected dropdown (Channel or ID)
* - Increases/decreases values using joystick Y-axis movement
* - Updates the internal data structure with selected values
* @details
* 1. Changes background color of dropdowns to indicate selection
* 2. Processes joystick Y-axis input for value modification
* 3. Updates dropdown selections and corresponding data values
* 4. Applies debouncing delay to prevent rapid value changes
*/
void update_setup_screen(joystick_data_t *data)
{
while (!lvgl_port_lock()) {
vTaskDelay(pdMS_TO_TICKS(10));
}
// Update setup screen
if (data->select_mode == CHANNEL_SELECT) {
lv_obj_set_style_bg_color(channel_dropdown, lv_color_make(255, 255, 0), LV_PART_MAIN); // Yellow
lv_obj_set_style_bg_color(id_dropdown, lv_color_make(255, 255, 255), LV_PART_MAIN); // White
} else if (data->select_mode == ID_SELECT) {
lv_obj_set_style_bg_color(channel_dropdown, lv_color_make(255, 255, 255), LV_PART_MAIN); // White
lv_obj_set_style_bg_color(id_dropdown, lv_color_make(255, 255, 0), LV_PART_MAIN); // Yellow
}
// In setup mode, joystick up/down controls value increment/decrement
if (data->joyY > Y_CENTER + DEAD_ZONE) {
// Move up - Increase Channel
if (data->select_mode == CHANNEL_SELECT) {
uint16_t selected = lv_dropdown_get_selected(channel_dropdown);
if (selected < 13) { // Maximum index is 13 (corresponding to Channel 14)
lv_dropdown_set_selected(channel_dropdown, selected + 1);
data->channel = selected + 2; // Index + 1 + 1 = displayed value
}
} else if (data->select_mode == ID_SELECT) {
uint16_t selected = lv_dropdown_get_selected(id_dropdown);
if (selected < 50) {
lv_dropdown_set_selected(id_dropdown, selected + 1);
data->id = selected + 1;
}
}
vTaskDelay(50 / portTICK_PERIOD_MS); // Add delay to prevent rapid changes
} else if (data->joyY < Y_CENTER - DEAD_ZONE) {
// Move down - Decrease Channel
if (data->select_mode == CHANNEL_SELECT) {
uint16_t selected = lv_dropdown_get_selected(channel_dropdown);
if (selected > 0) {
lv_dropdown_set_selected(channel_dropdown, selected - 1);
data->channel = selected; // Index - 1 + 1 = index itself
}
} else if (data->select_mode == ID_SELECT) {
uint16_t selected = lv_dropdown_get_selected(id_dropdown);
if (selected > 0) {
lv_dropdown_set_selected(id_dropdown, selected - 1);
data->id = selected - 1;
}
}
vTaskDelay(50 / portTICK_PERIOD_MS); // Add delay to prevent rapid changes
}
lvgl_port_unlock();
}
/**
* @brief Destroy the setup screen and reset all UI object pointers to NULL
* @note This function properly deletes the LVGL objects and resets internal pointers
* @details
* 1. Deletes the setup screen and all child objects using lv_obj_del
* 2. Sets all UI object pointers to NULL to prevent dangling references
*/
void ui_setup_screen_destory()
{
while (!lvgl_port_lock()) {
vTaskDelay(pdMS_TO_TICKS(10));
}
if (setup_screen != NULL) {
lv_obj_del(setup_screen);
setup_screen = NULL;
}
lvgl_port_unlock();
channel_label = NULL;
id_label = NULL;
channel_dropdown = NULL;
id_dropdown = NULL;
}