From be4e8b768f1961d7c1e70895f4057514024a8aee Mon Sep 17 00:00:00 2001 From: markmental Date: Sat, 28 Mar 2026 12:46:58 -0400 Subject: [PATCH] Add channel banner when switching channels --- src/app.c | 45 +++++++- src/app.h | 2 + src/app.o | Bin 14832 -> 15400 bytes src/channel.c | 67 +++++++++--- src/channel.h | 5 + src/channel.o | Bin 9432 -> 9872 bytes src/ui.c | 294 +++++++++++++++++++++++++++++++++++++++++--------- src/ui.h | 15 ++- src/ui.o | Bin 35896 -> 39512 bytes 9 files changed, 358 insertions(+), 70 deletions(-) diff --git a/src/app.c b/src/app.c index 2a7aff4..15bc799 100644 --- a/src/app.c +++ b/src/app.c @@ -9,6 +9,11 @@ #include #include +#define GUIDE_BROWSE_STEP_MINUTES 30 +#define GUIDE_BROWSE_MAX_AHEAD_MINUTES (12 * 60) +#define GUIDE_BROWSE_MAX_OFFSET_MINUTES (GUIDE_BROWSE_MAX_AHEAD_MINUTES - ((int) (TIMELINE_VISIBLE_SECONDS / 60.0) - 30)) +#define CHANNEL_BANNER_DURATION_MS 3000 + static void configure_runtime_environment(void) { char runtime_dir[64]; char pulse_socket[96]; @@ -135,6 +140,24 @@ static void tune_relative(App *app, int delta) { destroy_video_texture(app); begin_startup_handoff(app); player_tune(&app->player, next_index); + app->channel_banner_until = SDL_GetTicks() + CHANNEL_BANNER_DURATION_MS; +} + +static void browse_guide_time(App *app, int delta_minutes) { + int next_offset; + + if (!app || app->mode != MODE_GUIDE) { + return; + } + + next_offset = app->guide_time_offset_minutes + delta_minutes; + if (next_offset < 0) { + next_offset = 0; + } + if (next_offset > GUIDE_BROWSE_MAX_OFFSET_MINUTES) { + next_offset = GUIDE_BROWSE_MAX_OFFSET_MINUTES; + } + app->guide_time_offset_minutes = next_offset; } static void toggle_fullscreen(App *app) { @@ -230,6 +253,12 @@ static void handle_event(App *app, const SDL_Event *event) { case SDLK_DOWN: tune_relative(app, 1); break; + case SDLK_LEFT: + browse_guide_time(app, -GUIDE_BROWSE_STEP_MINUTES); + break; + case SDLK_RIGHT: + browse_guide_time(app, GUIDE_BROWSE_STEP_MINUTES); + break; default: break; } @@ -300,6 +329,7 @@ int app_init(App *app) { if (app->channels.count > 0) { begin_startup_handoff(app); player_tune(&app->player, 0); + app->channel_banner_until = SDL_GetTicks() + CHANNEL_BANNER_DURATION_MS; } return 0; @@ -356,9 +386,9 @@ void app_run(App *app) { &app->ui_cache, &app->channels, app->player.current_index, - app->app_start_ticks, - now_ticks, - now_wall); + app->app_start_time, + now_wall, + app->guide_time_offset_minutes); if (app->theme_picker_open) { ui_render_theme_picker(app->renderer, &app->fonts, @@ -383,7 +413,14 @@ void app_run(App *app) { app->texture_width, app->texture_height, output_width, - output_height); + output_height, + &GUIDE_THEMES[app->theme_index], + &app->fonts, + &app->channels, + app->player.current_index, + app->app_start_time, + now_wall, + SDL_GetTicks() < app->channel_banner_until); } SDL_RenderPresent(app->renderer); diff --git a/src/app.h b/src/app.h index 7ad2d10..8e4239b 100644 --- a/src/app.h +++ b/src/app.h @@ -24,8 +24,10 @@ typedef struct App { int startup_handoff_active; int last_blackout_state; Uint32 startup_handoff_until; + Uint32 channel_banner_until; time_t app_start_time; Uint64 app_start_ticks; + int guide_time_offset_minutes; ChannelList channels; Player player; UiFonts fonts; diff --git a/src/app.o b/src/app.o index b3f2dc433c1e75954a1d95c6d84b30447c266942..8688f4249f1aab05ce7657445d8be2f60b97d2f9 100644 GIT binary patch delta 6715 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 delta 6235 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 ORQ&XS@g%$8%=jPA@v!&+ diff --git a/src/channel.c b/src/channel.c index 38abc96..34c4f74 100644 --- a/src/channel.c +++ b/src/channel.c @@ -333,6 +333,16 @@ time_t channel_wall_time_from_ticks(time_t app_start_time, Uint64 app_start_tick return app_start_time + (time_t) (elapsed_ticks / 1000); } +double channel_schedule_elapsed_seconds(time_t app_start_time, time_t target_time) { + double elapsed = difftime(target_time, app_start_time); + + if (elapsed < 0.0) { + return 0.0; + } + + return elapsed; +} + double channel_live_position(const Channel *channel, time_t app_start_time, time_t now) { double elapsed; @@ -363,28 +373,33 @@ double channel_live_position_precise(const Channel *channel, Uint64 app_start_ti return fmod(elapsed, channel->total_duration_seconds); } -const ProgramEntry *channel_program_at_index(const Channel *channel, int program_index) { - if (!channel || program_index < 0 || program_index >= channel->program_count) { - return NULL; - } - return &channel->programs[program_index]; -} - -const ProgramEntry *channel_resolve_program(const Channel *channel, - Uint64 app_start_ticks, - Uint64 now_ticks, - double *program_seek_seconds, - int *program_index) { +const ProgramEntry *channel_resolve_program_at_elapsed(const Channel *channel, + double elapsed_seconds, + double *program_seek_seconds, + int *program_index) { double channel_offset; if (!channel || channel->program_count == 0 || channel->total_duration_seconds <= 0.0) { return NULL; } - channel_offset = channel_live_position_precise(channel, app_start_ticks, now_ticks); + if (elapsed_seconds < 0.0) { + elapsed_seconds = 0.0; + } + + channel_offset = fmod(elapsed_seconds, channel->total_duration_seconds); + if (channel_offset < 0.0) { + channel_offset += channel->total_duration_seconds; + } + for (int i = 0; i < channel->program_count; ++i) { const ProgramEntry *program = &channel->programs[i]; double end_offset = program->start_offset_seconds + program->duration_seconds; + + if (program->duration_seconds <= 0.0) { + continue; + } + if (channel_offset < end_offset || i == channel->program_count - 1) { if (program_seek_seconds) { *program_seek_seconds = channel_offset - program->start_offset_seconds; @@ -401,3 +416,29 @@ const ProgramEntry *channel_resolve_program(const Channel *channel, return &channel->programs[0]; } + +const ProgramEntry *channel_program_at_index(const Channel *channel, int program_index) { + if (!channel || program_index < 0 || program_index >= channel->program_count) { + return NULL; + } + return &channel->programs[program_index]; +} + +const ProgramEntry *channel_resolve_program(const Channel *channel, + Uint64 app_start_ticks, + Uint64 now_ticks, + double *program_seek_seconds, + int *program_index) { + double elapsed; + + if (!channel || channel->program_count == 0 || channel->total_duration_seconds <= 0.0) { + return NULL; + } + + if (now_ticks < app_start_ticks) { + now_ticks = app_start_ticks; + } + + elapsed = (double) (now_ticks - app_start_ticks) / 1000.0; + return channel_resolve_program_at_elapsed(channel, elapsed, program_seek_seconds, program_index); +} diff --git a/src/channel.h b/src/channel.h index a85cbb9..ed662b5 100644 --- a/src/channel.h +++ b/src/channel.h @@ -30,8 +30,13 @@ typedef struct ChannelList { int channel_list_load(ChannelList *list, const char *media_dir); void channel_list_destroy(ChannelList *list); time_t channel_wall_time_from_ticks(time_t app_start_time, Uint64 app_start_ticks, Uint64 now_ticks); +double channel_schedule_elapsed_seconds(time_t app_start_time, time_t target_time); double channel_live_position(const Channel *channel, time_t app_start_time, time_t now); double channel_live_position_precise(const Channel *channel, Uint64 app_start_ticks, Uint64 now_ticks); +const ProgramEntry *channel_resolve_program_at_elapsed(const Channel *channel, + double elapsed_seconds, + double *program_seek_seconds, + int *program_index); const ProgramEntry *channel_resolve_program(const Channel *channel, Uint64 app_start_ticks, Uint64 now_ticks, diff --git a/src/channel.o b/src/channel.o index e81015e35390c2a96763acd6b436f11c6d6f99ba..1732d0439172ddb50231e282a063231535d80a1d 100644 GIT binary patch delta 1452 zcmZ`%ZD?Cn7(Vy*7H`t@p1Wo?QQPI~4&$b6*%t8qXc&5Q+{)j}L%=ytq6B>HIA`=ZC$5qi?UMIbfFVfBsmnPn`cX^;`v?EYYj3XWsZD zB}DZ>WEQQSfI_1V`_8fE432F7kLDr;m^8dX^bZu#u-ur8EJAv3U$t7Lg}O*uzfR_> zsju@f%Lb-z9ltk{px7 z&bklH^oWs?x-QAzDS6E-wsQ5yPN^*;WNVgqB!is5!vb;8+ziZXVH!d-6ll(u@dcsY zxFnDqa46G2z}?&ce+`I3BTlpS8%rW=Gv0d1V#syo(bpEE$HEI1ZVU!zXDqy}-Xz+W zTCngD3)fJ-;puHIpq(B|#AhZF!-2ObTJg(u)O*6kVp)gAm} z77mw2jXUs5PvAG3Q|&{$g_f;x4I$d+`#U{my#$7^&$d3d3%3pbY8P%BF0x_>TgNuM zX%}uAj#{+Y$ySy8qJ5sKEiyH^Mg9Dd*L_kG{*`_9SsY<6aS z4Bxcq4_b0_mMa*>Y$v)>6*3jX2!;DEipqCi=FtEpsSjkTfnu3(4@8O*`I#5f+kqX4 zoLnNx3PMP1Ep?{XMG`HEM+;5NGejVVr}Dh{mDF>B)+J*iLfp)!e===e7h@fFIXu!JRYsZb7+ zdZW;j%FBjuniJEnMP=DX2MvaC99FGO(XEzBr6OfjIj~br#EZm*0{J2xV-&j6F@YD; zw*>ABT^4m`RGOibX8Q%xRx|AeJKLK}u(P;EP)neZYr!(KbIv}F@+^IwdX8y;+9*EO zwP6*zSZ;<1v%F%6u_2~xVfh%#MOc$)O|bmAY8Wf7N7;~Km|@^8cQCij%^S_nbico_ zWOw3Pm}_)K>KKF?5Jn}7mVBz$_;r2KstJ3$M0I^Z*N1T~;@H8C;pF(x!~Hulp?{WIsouTE&F<6p9yh;FU$8=?`3F7>0Z-68;neIo81)31 zxQ+g&1M(i99zGPRkzeSjnO7G9Y`4QC6<^xmiO|7p+TbgNU9B(V^;vfHeLrHj;XQ4h jc4_`5SoEGT5sif4mp5qU8#Oivfg?e4)~zuG7Co+i)I8+u diff --git a/src/ui.c b/src/ui.c index 9e772c3..769ba5e 100644 --- a/src/ui.c +++ b/src/ui.c @@ -12,6 +12,7 @@ static const char *FONT_CANDIDATES[] = { }; static void fill_rect(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color color); +static void stroke_rect(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color color); static SDL_Texture *text_to_texture(SDL_Renderer *renderer, TTF_Font *font, const char *text, SDL_Color color, int *width, int *height); static void text_texture_destroy(UiTextTexture *text_texture) { @@ -235,6 +236,37 @@ static void draw_beveled_bar(SDL_Renderer *renderer, SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); } +static void draw_program_block(SDL_Renderer *renderer, + const SDL_Rect *rect, + SDL_Color top, + SDL_Color mid, + SDL_Color bottom, + SDL_Color gloss, + SDL_Color border, + int is_selected, + SDL_Color selection_edge) { + SDL_Rect inner; + + if (!rect || rect->w <= 2 || rect->h <= 2) { + return; + } + + draw_beveled_bar(renderer, rect, top, mid, bottom, gloss, border); + stroke_rect(renderer, rect, border); + + inner = (SDL_Rect){rect->x + 1, rect->y + 1, rect->w - 2, rect->h - 2}; + if (inner.w > 1 && inner.h > 1) { + stroke_rect_alpha(renderer, &inner, color_with_alpha(COLOR_TEXT_LIGHT, is_selected ? 64 : 42)); + fill_rect_alpha(renderer, + &(SDL_Rect){inner.x + 1, inner.y + 1, SDL_max(inner.w - 2, 0), 2}, + color_with_alpha(COLOR_TEXT_LIGHT, is_selected ? 34 : 20)); + } + + if (is_selected) { + draw_selection_glow(renderer, rect, selection_edge); + } +} + static void draw_pill_button(SDL_Renderer *renderer, const GuideTheme *theme, const SDL_Rect *rect, SDL_Color fill, SDL_Color border) { SDL_Rect shadow; @@ -468,9 +500,8 @@ static void draw_info_panel(SDL_Renderer *renderer, const GuideTheme *theme, const Channel *selected_channel, const SDL_Rect *rect, - Uint64 app_start_ticks, - Uint64 now_ticks, - time_t now_wall) { + time_t app_start_time, + time_t guide_focus_time) { SDL_Rect accent; SDL_Rect clip_rect; char time_range[64]; @@ -495,11 +526,14 @@ static void draw_info_panel(SDL_Renderer *renderer, draw_panel_bevel(renderer, rect, theme->gloss); stroke_rect(renderer, rect, theme->panel_border); - program = channel_resolve_program(selected_channel, app_start_ticks, now_ticks, &program_seek, NULL); + program = channel_resolve_program_at_elapsed(selected_channel, + channel_schedule_elapsed_seconds(app_start_time, guide_focus_time), + &program_seek, + NULL); if (!program) { return; } - start_time = now_wall - (time_t) program_seek; + start_time = guide_focus_time - (time_t) program_seek; end_time = start_time + (time_t) program->duration_seconds; format_time_compact(time_range, sizeof(time_range), start_time); format_time_compact(end_text, sizeof(end_text), end_time); @@ -554,7 +588,7 @@ static void draw_footer_legend(SDL_Renderer *renderer, int window_width, int window_height) { SDL_Rect footer = {0, window_height - 54, window_width, 54}; - SDL_Rect chip = {window_width / 2 - 120, window_height - 38, 34, 20}; + SDL_Rect chip = {window_width / 2 - 220, window_height - 38, 34, 20}; SDL_Color footer_text = readable_text_color(theme->footer_mid); fill_three_stop_gradient(renderer, @@ -573,6 +607,11 @@ static void draw_footer_legend(SDL_Renderer *renderer, draw_pill_button(renderer, theme, &chip, theme->block_mid, theme->panel_border); draw_text_clipped(renderer, fonts->small, "B", &footer, chip.x + 11, chip.y + 2, footer_text); draw_text_clipped(renderer, fonts->small, "THEME", &footer, chip.x + 42, chip.y - 1, footer_text); + + chip.x += 160; + draw_pill_button(renderer, theme, &chip, theme->row_mid, theme->panel_border); + draw_text_clipped(renderer, fonts->small, "<>", &footer, chip.x + 5, chip.y + 2, footer_text); + draw_text_clipped(renderer, fonts->small, "TIME", &footer, chip.x + 42, chip.y - 1, footer_text); } static void draw_scanline_overlay(SDL_Renderer *renderer, int width, int height, const GuideTheme *theme) { @@ -582,6 +621,100 @@ static void draw_scanline_overlay(SDL_Renderer *renderer, int width, int height, (void) theme; } +static void draw_channel_status_banner(SDL_Renderer *renderer, + const UiFonts *fonts, + const GuideTheme *theme, + const ChannelList *channels, + int active_channel, + time_t app_start_time, + time_t now_wall, + int window_width, + int window_height) { + SDL_Rect banner; + SDL_Rect channel_pill; + SDL_Rect info_clip; + SDL_Color banner_text; + SDL_Color sub_text; + char channel_text[96]; + char time_range[64]; + char end_text[32]; + time_t start_time; + time_t end_time; + double program_seek = 0.0; + const Channel *channel; + const ProgramEntry *program; + + if (!renderer || !fonts || !theme || !channels || active_channel < 0 || active_channel >= channels->count) { + return; + } + + channel = &channels->items[active_channel]; + program = channel_resolve_program_at_elapsed(channel, + channel_schedule_elapsed_seconds(app_start_time, now_wall), + &program_seek, + NULL); + if (!program) { + return; + } + + banner = (SDL_Rect){window_width / 2 - 360, window_height - 92, 720, 64}; + if (banner.x < 24) { + banner.x = 24; + banner.w = window_width - 48; + } + channel_pill = (SDL_Rect){banner.x + 10, banner.y + 10, 210, banner.h - 20}; + info_clip = (SDL_Rect){channel_pill.x + channel_pill.w + 14, banner.y + 8, banner.w - channel_pill.w - 28, banner.h - 16}; + banner_text = ensure_contrast(theme->ribbon_text, theme->status_mid); + sub_text = ensure_contrast(theme->row_subtext, theme->status_mid); + + start_time = now_wall - (time_t) program_seek; + end_time = start_time + (time_t) program->duration_seconds; + format_time_compact(time_range, sizeof(time_range), start_time); + format_time_compact(end_text, sizeof(end_text), end_time); + strncat(time_range, " - ", sizeof(time_range) - strlen(time_range) - 1); + strncat(time_range, end_text, sizeof(time_range) - strlen(time_range) - 1); + snprintf(channel_text, sizeof(channel_text), "%s %d", channel->name, channel->number); + + draw_panel_shadow(renderer, &banner); + draw_beveled_bar(renderer, + &banner, + blend_color(theme->status_top, theme->status_mid, 220), + theme->status_mid, + blend_color(theme->status_bottom, theme->status_mid, 220), + 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)); + set_draw_color(renderer, theme->status_divider); + SDL_RenderDrawLine(renderer, + channel_pill.x + channel_pill.w + 6, + banner.y + 10, + channel_pill.x + channel_pill.w + 6, + banner.y + banner.h - 10); + draw_text_clipped(renderer, + fonts->medium, + program->program_title, + &info_clip, + info_clip.x, + banner.y + 10, + banner_text); + draw_text_clipped(renderer, + fonts->small, + time_range, + &info_clip, + info_clip.x, + banner.y + 36, + sub_text); +} + void ui_render_about_modal(SDL_Renderer *renderer, const UiFonts *fonts, int window_width, @@ -668,10 +801,28 @@ void ui_render_fullscreen(SDL_Renderer *renderer, int texture_width, int texture_height, int window_width, - int window_height) { + int window_height, + const GuideTheme *theme, + const UiFonts *fonts, + const ChannelList *channels, + int active_channel, + time_t app_start_time, + time_t now_wall, + int show_channel_banner) { 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); + if (show_channel_banner) { + draw_channel_status_banner(renderer, + fonts, + theme, + channels, + active_channel, + app_start_time, + now_wall, + window_width, + window_height); + } } void ui_render_guide(SDL_Renderer *renderer, @@ -685,9 +836,9 @@ void ui_render_guide(SDL_Renderer *renderer, UiCache *cache, const ChannelList *channels, int active_channel, - Uint64 app_start_ticks, - Uint64 now_ticks, - time_t now_wall) { + time_t app_start_time, + time_t now_wall, + int guide_time_offset_minutes) { double scale_x = (double) window_width / WINDOW_WIDTH; double scale_y = (double) window_height / WINDOW_HEIGHT; int guide_x_start = (int) (GUIDE_X_START * scale_x); @@ -703,7 +854,11 @@ void ui_render_guide(SDL_Renderer *renderer, int start_index = active_channel - 2; const Channel *selected_channel = NULL; double pixels_per_minute = timeline_w / 90.0; - time_t guide_view_start_time = now_wall - (30 * 60); + time_t guide_view_start_time = now_wall - (30 * 60) + (guide_time_offset_minutes * 60); + time_t guide_focus_time = guide_view_start_time + (30 * 60); + double guide_view_start_seconds = channel_schedule_elapsed_seconds(app_start_time, guide_view_start_time); + double guide_view_end_seconds = guide_view_start_seconds + TIMELINE_VISIBLE_SECONDS; + double guide_focus_seconds = channel_schedule_elapsed_seconds(app_start_time, guide_focus_time); if (channels && channels->count > 0 && active_channel >= 0 && active_channel < channels->count) { selected_channel = &channels->items[active_channel]; @@ -714,20 +869,20 @@ void ui_render_guide(SDL_Renderer *renderer, theme->background_top, theme->background_mid, theme->background_bottom); - draw_info_panel(renderer, fonts, theme, selected_channel, &info_panel, app_start_ticks, now_ticks, now_wall); + draw_info_panel(renderer, fonts, theme, selected_channel, &info_panel, app_start_time, guide_focus_time); draw_panel_shadow(renderer, &preview); fill_rect(renderer, &preview, COLOR_BLACK); draw_video(renderer, video_texture, texture_width, texture_height, preview); draw_status_bar(renderer, fonts->medium, theme, selected_channel, &status_bar, now_wall); - if (cache->timeline_label_slot != now_wall / 60 || cache->timeline_theme != theme) { + if (cache->timeline_label_slot != guide_view_start_time / 60 || cache->timeline_theme != theme) { char label[32]; for (int i = 0; i < 4; ++i) { format_clock_label(label, sizeof(label), guide_view_start_time, 30 * i); text_texture_destroy(&cache->timeline_labels[i]); text_texture_init(&cache->timeline_labels[i], renderer, fonts->small, label, COLOR_TEXT_LIGHT); } - cache->timeline_label_slot = now_wall / 60; + cache->timeline_label_slot = guide_view_start_time / 60; cache->timeline_theme = theme; } draw_timeline_header_cached(renderer, @@ -778,14 +933,8 @@ void ui_render_guide(SDL_Renderer *renderer, { const Channel *channel = &channels->items[channel_index]; - double program_seek = 0.0; - const ProgramEntry *program = channel_resolve_program(channel, app_start_ticks, now_ticks, &program_seek, NULL); - double guide_view_start_seconds = (double) guide_view_start_time; - double program_start_time = (double) now_wall; - int block_x = guide_x_start; - int block_w = 48; - SDL_Rect block = {guide_x_start, timeline_rect.y + 4, 48, timeline_rect.h - 8}; - SDL_Rect title_rect = {block.x + 8, block.y + 8, block.w - 16, block.h - 16}; + double focus_program_seek = 0.0; + const ProgramEntry *focus_program = channel_resolve_program_at_elapsed(channel, guide_focus_seconds, &focus_program_seek, NULL); char title[128]; SDL_Color row_primary = ensure_contrast(is_selected ? theme->row_active_text : theme->row_text, is_selected ? theme->row_active_mid : theme->row_mid); @@ -797,14 +946,9 @@ void ui_render_guide(SDL_Renderer *renderer, ? color_with_alpha(COLOR_BLACK, 255) : color_with_alpha(COLOR_TEXT_LIGHT, 255); - if (!program) { + if (!focus_program) { continue; } - program_start_time -= program_seek; - block_x = guide_x_start + (int) ((((program_start_time - guide_view_start_seconds) / 60.0) * pixels_per_minute) + 0.5); - block_w = (int) ((program->duration_seconds / 60.0) * pixels_per_minute); - block = (SDL_Rect){block_x, timeline_rect.y + 4, SDL_max(block_w, 48), timeline_rect.h - 8}; - title_rect = (SDL_Rect){block.x + 8, block.y + 8, block.w - 16, block.h - 16}; if (is_selected) { draw_text_shadowed(renderer, fonts->medium, channel->name, &sidebar, 20, row_rect.y + 12, row_primary, color_with_alpha(COLOR_BLACK, 255)); @@ -823,7 +967,7 @@ void ui_render_guide(SDL_Renderer *renderer, } draw_text_shadowed(renderer, fonts->small, - program->file_name, + focus_program->file_name, &sidebar, 20, row_rect.y + 38, @@ -831,26 +975,78 @@ void ui_render_guide(SDL_Renderer *renderer, color_with_alpha(COLOR_BLACK, 255)); SDL_RenderSetClipRect(renderer, &clip); - draw_beveled_bar(renderer, - &block, - is_selected ? theme->block_active_top : theme->block_top, - is_selected ? theme->block_active_mid : theme->block_mid, - is_selected ? theme->block_active_bottom : theme->block_bottom, - is_selected ? theme->selection_edge : theme->gloss, - theme->panel_border); - fit_text_with_ellipsis(is_selected ? fonts->medium : fonts->small, - program->program_title, - title_rect.w, - title, - sizeof(title)); - draw_text_shadowed(renderer, - is_selected ? fonts->medium : fonts->small, - title, - &title_rect, - title_rect.x, - title_rect.y, - block_text, - block_shadow); + + { + double block_cursor_seconds = guide_view_start_seconds; + int block_guard = channel->program_count; + + if (channel->total_duration_seconds > 0.0) { + block_guard *= 1 + (int) (TIMELINE_VISIBLE_SECONDS / channel->total_duration_seconds); + } + block_guard += 8; + if (block_guard < 16) { + block_guard = 16; + } + + while (block_cursor_seconds < guide_view_end_seconds && block_guard-- > 0) { + double program_seek = 0.0; + const ProgramEntry *program = channel_resolve_program_at_elapsed(channel, block_cursor_seconds, &program_seek, NULL); + double program_start_seconds; + double program_end_seconds; + double visible_start_seconds; + double visible_end_seconds; + int block_x; + int block_w; + SDL_Rect block; + SDL_Rect title_rect; + + if (!program || program->duration_seconds <= 0.0) { + break; + } + + program_start_seconds = block_cursor_seconds - program_seek; + program_end_seconds = program_start_seconds + program->duration_seconds; + visible_start_seconds = SDL_max(program_start_seconds, guide_view_start_seconds); + visible_end_seconds = SDL_min(program_end_seconds, guide_view_end_seconds); + + block_cursor_seconds = program_end_seconds; + if (visible_end_seconds <= visible_start_seconds) { + continue; + } + + block_x = guide_x_start + (int) ((((visible_start_seconds - guide_view_start_seconds) / 60.0) * pixels_per_minute) + 0.5); + block_w = (int) ((((visible_end_seconds - visible_start_seconds) / 60.0) * pixels_per_minute) + 0.5); + block = (SDL_Rect){block_x + 1, timeline_rect.y + 4, SDL_max(block_w - 2, 22), timeline_rect.h - 8}; + title_rect = (SDL_Rect){block.x + 8, block.y + 8, block.w - 16, block.h - 16}; + + draw_program_block(renderer, + &block, + is_selected ? theme->block_active_top : theme->block_top, + is_selected ? theme->block_active_mid : theme->block_mid, + is_selected ? theme->block_active_bottom : theme->block_bottom, + theme->gloss, + theme->panel_border, + is_selected, + theme->selection_edge); + + if (title_rect.w > 24) { + fit_text_with_ellipsis(is_selected ? fonts->medium : fonts->small, + program->program_title, + title_rect.w, + title, + sizeof(title)); + draw_text_shadowed(renderer, + is_selected ? fonts->medium : fonts->small, + title, + &title_rect, + title_rect.x, + title_rect.y, + block_text, + block_shadow); + } + } + } + SDL_RenderSetClipRect(renderer, NULL); } } diff --git a/src/ui.h b/src/ui.h index c716f65..61b5547 100644 --- a/src/ui.h +++ b/src/ui.h @@ -52,7 +52,14 @@ void ui_render_fullscreen(SDL_Renderer *renderer, int texture_width, int texture_height, int window_width, - int window_height); + int window_height, + const GuideTheme *theme, + const UiFonts *fonts, + const ChannelList *channels, + int active_channel, + time_t app_start_time, + time_t now_wall, + int show_channel_banner); void ui_render_guide(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, @@ -64,9 +71,9 @@ void ui_render_guide(SDL_Renderer *renderer, UiCache *cache, const ChannelList *channels, int active_channel, - Uint64 app_start_ticks, - Uint64 now_ticks, - time_t now_wall); + time_t app_start_time, + time_t now_wall, + int guide_time_offset_minutes); void ui_render_theme_picker(SDL_Renderer *renderer, const UiFonts *fonts, int window_width, diff --git a/src/ui.o b/src/ui.o index 470287a665f14624b13df3b625efd254ef1f5b34..b82cf0ab49d89efc0e1c2f14b7bc870d9734456a 100644 GIT binary patch literal 39512 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 M{>w}#!f^ZjFDdXaHvj+t literal 35896 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%0ADS(oWk?F<py(} ze657bdVV8tYM<9i`rF0gh48Twe!YadB>XlBzfQvMlJM&#{NKcai}Wv)@Fyf(ZnwXY zaJl{eLBeG|-2>oJbjKNv>&G20Rv@ zr32tkNw{00|9${`JYDL5BmU#?Sp16zz#o_J@e=*f0q|@2Pgza=H%jy?2f%+L;c*iE zaIt?udd5rmDS?OA%l8s4m**8?zk~QpkoZgxIPsCk_nRg9A4v2I2B2Ri(NC1<*9}0w zL&D|u&>`Wn{xf316pr+tgvY8cO~PqU-@<(oo*?1H5>7#jzFER2OZYbuo+#mV5(Y>5 zB;m36jFs>y67H4osS;i(;mHzypM+17@ZU@LbP1n)H9p`-pPTSl`g|kdDH5*Hq!})} z{p3oxT>e98Fc$Q**KF~>PQuG2yjH^H`u&517fbZJ1y1^>O8EN{eT9TSOvV?E^q2M7 zEa9>~FH87hq_OlrCUBA~njS(n+pk>Qj_|Em%%({Ci>4o7@$!(;JzQs5+4Zs&Dm^x+7X*S|?*#Ni09!ejBt zlJIH?e?s6Smo5uh^v_B3vfLI4m-)X)g8^K)KJ{eu;fVhjJQn|0GQMzxr{S^iB?2ct za(&fE_!5c!j}jkM!VgP0H5rTlG&16FBsU$8h2JIN84|uz;G|EXgddi0Sm)q5O z377f2K!XPy>7(JX^m$3(Bv&r~xiomd5j~l3i~h#~4==Z8BwW^Kr^Lr2@mWBF5L`H) zB@(^_@s`|2B)n3>4@>yn5`IG9q`y4w45C2}j^xVrd4hz?d@?0mrk^9>ay!3E;3PK_ zkEMT!M1PNjS4z0d=iek;rhio8KU3oK9}=!f_^T2hxqjc3=yi$yWg67sNPpQrye@Dm zH=ihbr&q!cNcb!X|4zbZOZZrtl)#1SKUKnIJ<}vy)^nDG7lNOq zXK(=g83~v9KQG}j|7Ho7`QJ{16CCL;^YKZz%;!mgQ@Q!@SbF|i!fB~NV>7wa5}t)` zi~hXCUv9TQrokRAT%V^Tdk@l$B-i2r;E zze3<7Pi}|fBzietKbCMRLW}>?1MqoIqL=H7PkNBv$}fW4<))jygSE&J$|~)T{s>y0PYbu=|lF!lDk5pzgNN^7y#cm0RDo6uafxG4#fu?=~;-! zl8YdBcDxllyUowuer)000(T1E!ec1_7i)UB>0t875x6T1uM>EhgvTI!T6}W`2oo9M z^cNk;wF=+DuM*$&RFH5MeuKc%BKzZs0=Eo~MSr`%TSddLa7+LCLH+qG7W8SC^~diP zxOFww;$!94Ws>vuDOBbN^$~J}(Nm9yT#M=T;vIs&RUQ`oX2HxY;w{{|2b~gzcZhPS z4#Um=alvMLHw^E%+*HIRxNgwuIVySNMyT!1vdf z{&Fise{UdxuJYItii`Y3wuB|MwYG#B9P;~%h&%~@!=m3OZes8>oB$z2Ch${zi_G#9 zme%^|eu?0PFC<-BwSxXEgDs)5%3qQ&Gdpimt-ok#x!_r{yr2|+_@czj&j0h<1rF3? zM6vYpOB12P8NCn>SoXt0uR(yiUYZ36KXJJk(1`$!(vci%eqq_0@d6jk0bi!OL9;^r zebKyo!HEbF&;M