From 1034e31a446b0757121329ec10da26d3e4d510f5 Mon Sep 17 00:00:00 2001 From: markmental Date: Sat, 28 Mar 2026 17:35:13 -0400 Subject: [PATCH] Initial add of numeric channel switching --- src/app.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/app.h | 4 ++ src/app.o | Bin 15560 -> 19264 bytes src/ui.c | 58 ++++++++++++++++++++------ src/ui.h | 5 ++- src/ui.o | Bin 39352 -> 39712 bytes 6 files changed, 172 insertions(+), 16 deletions(-) diff --git a/src/app.c b/src/app.c index e7e60df..2e74966 100644 --- a/src/app.c +++ b/src/app.c @@ -14,6 +14,7 @@ #define GUIDE_BROWSE_MAX_OFFSET_MINUTES (GUIDE_BROWSE_MAX_AHEAD_MINUTES - ((int) (TIMELINE_VISIBLE_SECONDS / 60.0) - 30)) #define CHANNEL_BANNER_DURATION_MS 5000 #define CHANNEL_SWITCH_LOCK_DURATION_MS 7000 +#define NUMERIC_INPUT_TIMEOUT_MS 1000 static void configure_runtime_environment(void) { char runtime_dir[64]; @@ -141,16 +142,106 @@ static void tune_relative(App *app, int delta) { app->channel_switch_lock_until = now + CHANNEL_SWITCH_LOCK_DURATION_MS; next_index = app->player.current_index; + fprintf(stderr, "[DEBUG tune_relative] current_index=%d, delta=%d\n", next_index, delta); if (next_index < 0) { next_index = 0; } next_index = (next_index + delta + app->channels.count) % app->channels.count; + fprintf(stderr, "[DEBUG tune_relative] calculated next_index=%d\n", next_index); destroy_video_texture(app); begin_startup_handoff(app); player_tune(&app->player, next_index); + fprintf(stderr, "[DEBUG tune_relative] after player_tune, current_index=%d\n", app->player.current_index); app->channel_banner_until = SDL_GetTicks() + CHANNEL_BANNER_DURATION_MS; } +static int find_channel_by_number(const ChannelList *channels, int number) { + for (int i = 0; i < channels->count; i++) { + if (channels->items[i].number == number) { + return i; + } + } + return -1; +} + +static void tune_to_channel(App *app, int channel_index) { + Uint32 now; + + if (app->channels.count == 0 || channel_index < 0 || channel_index >= app->channels.count) { + return; + } + + fprintf(stderr, "[DEBUG tune_to_channel] requested channel_index=%d, current_index=%d\n", channel_index, app->player.current_index); + now = SDL_GetTicks(); + if (now < app->channel_switch_lock_until) { + fprintf(stderr, "[DEBUG tune_to_channel] LOCKED, aborting\n"); + return; + } + app->channel_switch_lock_until = now + CHANNEL_SWITCH_LOCK_DURATION_MS; + + destroy_video_texture(app); + begin_startup_handoff(app); + player_tune(&app->player, channel_index); + fprintf(stderr, "[DEBUG tune_to_channel] after player_tune, current_index=%d\n", app->player.current_index); + app->channel_banner_until = SDL_GetTicks() + CHANNEL_BANNER_DURATION_MS; +} + +static void process_numeric_input(App *app) { + int target_number; + int channel_index; + + if (app->numeric_input_length == 0) { + return; + } + + target_number = atoi(app->numeric_input_buffer); + fprintf(stderr, "[DEBUG process_numeric_input] input='%s', target_number=%d, current_index=%d\n", + app->numeric_input_buffer, target_number, app->player.current_index); + channel_index = find_channel_by_number(&app->channels, target_number); + fprintf(stderr, "[DEBUG process_numeric_input] found channel_index=%d for number %d\n", channel_index, target_number); + + if (channel_index >= 0) { + tune_to_channel(app, channel_index); + app->numeric_input_invalid = 0; + } else { + app->numeric_input_invalid = 1; + app->channel_banner_until = SDL_GetTicks() + CHANNEL_BANNER_DURATION_MS; + } + + app->numeric_input_length = 0; + app->numeric_input_buffer[0] = '\0'; +} + +static void handle_numeric_key(App *app, int digit) { + Uint32 now; + + if (app->channels.count == 0) { + return; + } + + now = SDL_GetTicks(); + + if (now < app->channel_switch_lock_until) { + return; + } + + if (app->numeric_input_length == 0) { + app->numeric_input_timeout = now + NUMERIC_INPUT_TIMEOUT_MS; + app->numeric_input_invalid = 0; + } + + if (app->numeric_input_length < 3) { + app->numeric_input_buffer[app->numeric_input_length] = '0' + digit; + app->numeric_input_length++; + app->numeric_input_buffer[app->numeric_input_length] = '\0'; + app->channel_banner_until = SDL_GetTicks() + CHANNEL_BANNER_DURATION_MS; + } + + if (app->numeric_input_length >= 3) { + process_numeric_input(app); + } +} + static void browse_guide_time(App *app, int delta_minutes) { int next_offset; @@ -256,10 +347,10 @@ static void handle_event(App *app, const SDL_Event *event) { app->about_modal_open = !app->about_modal_open; break; case SDLK_UP: - tune_relative(app, -1); + tune_relative(app, 1); break; case SDLK_DOWN: - tune_relative(app, 1); + tune_relative(app, -1); break; case SDLK_LEFT: browse_guide_time(app, -GUIDE_BROWSE_STEP_MINUTES); @@ -267,6 +358,14 @@ static void handle_event(App *app, const SDL_Event *event) { case SDLK_RIGHT: browse_guide_time(app, GUIDE_BROWSE_STEP_MINUTES); break; + case SDLK_0: case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: + case SDLK_5: case SDLK_6: case SDLK_7: case SDLK_8: case SDLK_9: + handle_numeric_key(app, event->key.keysym.sym - SDLK_0); + break; + case SDLK_KP_0: case SDLK_KP_1: case SDLK_KP_2: case SDLK_KP_3: case SDLK_KP_4: + case SDLK_KP_5: case SDLK_KP_6: case SDLK_KP_7: case SDLK_KP_8: case SDLK_KP_9: + handle_numeric_key(app, event->key.keysym.sym - SDLK_KP_0); + break; default: break; } @@ -357,6 +456,10 @@ void app_run(App *app) { handle_event(app, &event); } + if (app->numeric_input_length > 0 && SDL_GetTicks() >= app->numeric_input_timeout) { + process_numeric_input(app); + } + if (update_video_texture(app) != 0) { app->running = 0; break; @@ -370,6 +473,15 @@ void app_run(App *app) { in_blackout = player_is_in_blackout(&app->player); now_ticks = SDL_GetTicks64(); now_wall = channel_wall_time_from_ticks(app->app_start_time, app->app_start_ticks, now_ticks); + + static Uint32 last_debug_print = 0; + if (now_ticks - last_debug_print > 1000) { + fprintf(stderr, "[DEBUG main_loop] current_index=%d, channel_number=%d, lock_remaining=%d\n", + app->player.current_index, + app->player.current_index >= 0 ? app->channels.items[app->player.current_index].number : -1, + (int)(app->channel_switch_lock_until - SDL_GetTicks())); + last_debug_print = now_ticks; + } if (app->last_blackout_state && !in_blackout) { app->startup_handoff_active = 1; app->startup_handoff_until = SDL_GetTicks() + 400; @@ -428,7 +540,10 @@ void app_run(App *app) { app->player.current_index, app->app_start_time, now_wall, - SDL_GetTicks() < app->channel_banner_until); + SDL_GetTicks() < app->channel_banner_until, + app->numeric_input_buffer, + app->numeric_input_length, + app->numeric_input_invalid); } SDL_RenderPresent(app->renderer); diff --git a/src/app.h b/src/app.h index aaa871e..8660600 100644 --- a/src/app.h +++ b/src/app.h @@ -29,6 +29,10 @@ typedef struct App { time_t app_start_time; Uint64 app_start_ticks; int guide_time_offset_minutes; + char numeric_input_buffer[4]; + int numeric_input_length; + Uint32 numeric_input_timeout; + int numeric_input_invalid; ChannelList channels; Player player; UiFonts fonts; diff --git a/src/app.o b/src/app.o index 3984271c121a3e0e819eb4bdd29afb549bcc6e6f..ee973f62ac876bd531bd1b9878ba6de9e2db4d8d 100644 GIT binary patch literal 19264 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

px5W9 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 diff --git a/src/ui.c b/src/ui.c index e2f9e6c..aed51aa 100644 --- a/src/ui.c +++ b/src/ui.c @@ -634,7 +634,10 @@ static void draw_channel_status_banner(SDL_Renderer *renderer, time_t app_start_time, time_t now_wall, int window_width, - int window_height) { + int window_height, + const char *numeric_input_buffer, + int numeric_input_length, + int numeric_input_invalid) { SDL_Rect banner; SDL_Rect channel_pill; SDL_Rect info_clip; @@ -643,6 +646,7 @@ static void draw_channel_status_banner(SDL_Renderer *renderer, char channel_text[96]; char time_range[64]; char end_text[32]; + char numeric_display[8]; time_t start_time; time_t end_time; double program_seek = 0.0; @@ -689,15 +693,39 @@ static void draw_channel_status_banner(SDL_Renderer *renderer, color_with_alpha(theme->gloss, 42), theme->panel_border); stroke_rect(renderer, &banner, theme->panel_border); - draw_pill_button(renderer, theme, &channel_pill, theme->panel_fill, theme->panel_border); - draw_text_shadowed(renderer, - fonts->medium, - channel_text, - &channel_pill, - channel_pill.x + 14, - channel_pill.y + 8, - ensure_contrast(theme->panel_text, theme->panel_fill), - color_with_alpha(COLOR_BLACK, 255)); + + if (numeric_input_length > 0 || numeric_input_invalid) { + SDL_Color accent_fill = theme->ribbon_mid; + SDL_Color accent_border = theme->ribbon_bottom; + SDL_Color text_color = COLOR_TEXT_LIGHT; + + if (numeric_input_invalid) { + snprintf(numeric_display, sizeof(numeric_display), "???"); + } else { + snprintf(numeric_display, sizeof(numeric_display), "%s_", numeric_input_buffer); + } + + draw_pill_button(renderer, theme, &channel_pill, accent_fill, accent_border); + draw_text_shadowed(renderer, + fonts->medium, + numeric_display, + &channel_pill, + channel_pill.x + 14, + channel_pill.y + 8, + text_color, + color_with_alpha(COLOR_BLACK, 255)); + } else { + draw_pill_button(renderer, theme, &channel_pill, theme->panel_fill, theme->panel_border); + draw_text_shadowed(renderer, + fonts->medium, + channel_text, + &channel_pill, + channel_pill.x + 14, + channel_pill.y + 8, + ensure_contrast(theme->panel_text, theme->panel_fill), + color_with_alpha(COLOR_BLACK, 255)); + } + set_draw_color(renderer, theme->status_divider); SDL_RenderDrawLine(renderer, channel_pill.x + channel_pill.w + 6, @@ -813,7 +841,10 @@ void ui_render_fullscreen(SDL_Renderer *renderer, int active_channel, time_t app_start_time, time_t now_wall, - int show_channel_banner) { + int show_channel_banner, + const char *numeric_input_buffer, + int numeric_input_length, + int numeric_input_invalid) { SDL_Rect window = {0, 0, window_width, window_height}; fill_rect(renderer, &window, COLOR_BLACK); draw_video(renderer, video_texture, texture_width, texture_height, window); @@ -826,7 +857,10 @@ void ui_render_fullscreen(SDL_Renderer *renderer, app_start_time, now_wall, window_width, - window_height); + window_height, + numeric_input_buffer, + numeric_input_length, + numeric_input_invalid); } } diff --git a/src/ui.h b/src/ui.h index 61b5547..e54039c 100644 --- a/src/ui.h +++ b/src/ui.h @@ -59,7 +59,10 @@ void ui_render_fullscreen(SDL_Renderer *renderer, int active_channel, time_t app_start_time, time_t now_wall, - int show_channel_banner); + int show_channel_banner, + const char *numeric_input_buffer, + int numeric_input_length, + int numeric_input_invalid); void ui_render_guide(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, diff --git a/src/ui.o b/src/ui.o index 10f7827931e023d31ebaa1045c379415dd843f06..ddb19a94939796b88ce1ce25c341f07fbb3519a8 100644 GIT binary patch delta 10755 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 delta 10374 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