|
14 | 14 | #define SPLASH_FRAME_RATE 60 // Target 60 FPS |
15 | 15 | #define SPLASH_FRAME_DELAY_MS (1000 / SPLASH_FRAME_RATE) |
16 | 16 |
|
| 17 | +// Typing animation configuration |
| 18 | +#define TYPING_SPEED_MS 14 // <n> ms per character |
| 19 | +#define TYPING_DISPLAY_TIME_MS 1200 // <n>> seconds display time |
| 20 | +#define TYPING_DELETE_SPEED_MS 10 // <n> ms per character deletion |
| 21 | + |
17 | 22 | // Color definitions |
18 | 23 | #define SPLASH_BG_DARK 0xFF0A0A0A |
19 | 24 | #define SPLASH_CYAN_BORDER 0xFF00FFFF |
|
26 | 31 | #define LOGO_BORDER_WIDTH 10 |
27 | 32 | #define LOGO_BORDER_RADIUS 15 |
28 | 33 |
|
| 34 | +// Typing animation states |
| 35 | +typedef enum { |
| 36 | + TYPING_STATE_IDLE, |
| 37 | + TYPING_STATE_TYPING, |
| 38 | + TYPING_STATE_DISPLAY, |
| 39 | + TYPING_STATE_DELETING |
| 40 | +} typing_state_t; |
| 41 | + |
29 | 42 | static void create_dark_background(stlxgfx_surface_t* surface) { |
30 | 43 | if (!surface) return; |
31 | 44 | stlxgfx_clear_surface(surface, SPLASH_BG_DARK); |
@@ -162,6 +175,97 @@ static void add_modern_decorative_elements(stlxgfx_surface_t* surface, uint32_t |
162 | 175 | logo_y + LOGO_HEIGHT + LOGO_BORDER_WIDTH + corner_size - 2, corner_size, 2, corner_color); |
163 | 176 | } |
164 | 177 |
|
| 178 | +static void draw_typing_animation(stlxgfx_surface_t* surface, stlxgfx_context_t* gfx_ctx, |
| 179 | + uint32_t frame, uint32_t elapsed_ms) { |
| 180 | + if (!surface || !gfx_ctx) return; |
| 181 | + |
| 182 | + static typing_state_t state = TYPING_STATE_IDLE; |
| 183 | + static uint32_t state_start_time = 0; |
| 184 | + static uint32_t current_length = 0; |
| 185 | + static uint32_t last_animation_time = 0; |
| 186 | + (void) frame; |
| 187 | + |
| 188 | + const char* full_text = "User: root"; |
| 189 | + const uint32_t full_length = strlen(full_text); |
| 190 | + |
| 191 | + // Initialize state timing |
| 192 | + if (state == TYPING_STATE_IDLE) { |
| 193 | + state = TYPING_STATE_TYPING; |
| 194 | + state_start_time = elapsed_ms; |
| 195 | + current_length = 0; |
| 196 | + last_animation_time = elapsed_ms; |
| 197 | + } |
| 198 | + |
| 199 | + // Calculate position in the middle of the gradient rectangle |
| 200 | + uint32_t center_x = surface->width / 2; |
| 201 | + uint32_t logo_y = surface->height / 3; |
| 202 | + uint32_t logo_x = center_x - LOGO_WIDTH / 2; |
| 203 | + uint32_t text_x = logo_x + LOGO_WIDTH / 2; |
| 204 | + uint32_t text_y = logo_y + LOGO_HEIGHT / 2 - 4; |
| 205 | + |
| 206 | + // Handle state transitions |
| 207 | + switch (state) { |
| 208 | + case TYPING_STATE_TYPING: { |
| 209 | + // Type out characters |
| 210 | + if (elapsed_ms - last_animation_time >= TYPING_SPEED_MS) { |
| 211 | + if (current_length < full_length) { |
| 212 | + current_length++; |
| 213 | + last_animation_time = elapsed_ms; |
| 214 | + } else { |
| 215 | + // Finished typing, move to display state |
| 216 | + state = TYPING_STATE_DISPLAY; |
| 217 | + state_start_time = elapsed_ms; |
| 218 | + } |
| 219 | + } |
| 220 | + break; |
| 221 | + } |
| 222 | + |
| 223 | + case TYPING_STATE_DISPLAY: { |
| 224 | + // Display full text for 2 seconds |
| 225 | + if (elapsed_ms - state_start_time >= TYPING_DISPLAY_TIME_MS) { |
| 226 | + state = TYPING_STATE_DELETING; |
| 227 | + state_start_time = elapsed_ms; |
| 228 | + last_animation_time = elapsed_ms; |
| 229 | + } |
| 230 | + break; |
| 231 | + } |
| 232 | + |
| 233 | + case TYPING_STATE_DELETING: { |
| 234 | + // Delete characters one by one |
| 235 | + if (elapsed_ms - last_animation_time >= TYPING_DELETE_SPEED_MS) { |
| 236 | + if (current_length > 0) { |
| 237 | + current_length--; |
| 238 | + last_animation_time = elapsed_ms; |
| 239 | + } else { |
| 240 | + // Finished deleting, restart typing |
| 241 | + state = TYPING_STATE_TYPING; |
| 242 | + state_start_time = elapsed_ms; |
| 243 | + last_animation_time = elapsed_ms; |
| 244 | + } |
| 245 | + } |
| 246 | + break; |
| 247 | + } |
| 248 | + |
| 249 | + default: |
| 250 | + break; |
| 251 | + } |
| 252 | + |
| 253 | + // Draw the current text |
| 254 | + if (current_length > 0) { |
| 255 | + // Create temporary string with current length |
| 256 | + char temp_text[32]; |
| 257 | + strncpy(temp_text, full_text, current_length); |
| 258 | + temp_text[current_length] = '\0'; |
| 259 | + |
| 260 | + // Calculate text width for centering |
| 261 | + uint32_t text_width = current_length * 16 * 0.6f; // Approximate width |
| 262 | + uint32_t draw_x = text_x - text_width / 2; |
| 263 | + |
| 264 | + // Draw the typing text in bright green |
| 265 | + stlxgfx_render_text(gfx_ctx, surface, temp_text, draw_x, text_y, 18, SPLASH_WHITE_BRIGHT); |
| 266 | + } |
| 267 | +} |
| 268 | + |
165 | 269 | static int check_for_enter_key() { |
166 | 270 | input_event_t events[16]; |
167 | 271 | int n = stlx_read_input_events(STLXGFX_INPUT_QUEUE_ID_SYSTEM, 0, events, 16); |
@@ -206,11 +310,13 @@ int stlxdm_show_splash_screen(stlxdm_compositor_t* compositor) { |
206 | 310 | } |
207 | 311 |
|
208 | 312 | uint32_t frame = 0; |
| 313 | + uint32_t elapsed_ms = 0; |
209 | 314 | printf("[STLXDM_SPLASH] Displaying splash screen (press Enter to continue)\n"); |
210 | 315 |
|
211 | 316 | while (1) { |
212 | 317 | create_dark_background(splash_surface); |
213 | 318 | draw_animated_gradient_logo(splash_surface, frame); |
| 319 | + draw_typing_animation(splash_surface, compositor->gfx_ctx, frame, elapsed_ms); |
214 | 320 | draw_cyan_border(splash_surface); |
215 | 321 | draw_static_title(splash_surface, compositor->gfx_ctx); |
216 | 322 | draw_breathing_text(splash_surface, compositor->gfx_ctx, frame); |
@@ -240,6 +346,7 @@ int stlxdm_show_splash_screen(stlxdm_compositor_t* compositor) { |
240 | 346 | nanosleep(&delay, NULL); |
241 | 347 |
|
242 | 348 | frame++; |
| 349 | + elapsed_ms += SPLASH_FRAME_DELAY_MS; |
243 | 350 | } |
244 | 351 |
|
245 | 352 | stlxgfx_dm_destroy_surface(compositor->gfx_ctx, splash_surface); |
|
0 commit comments