From 215439621c14bc1002cf6e05db62655e48f3df4c Mon Sep 17 00:00:00 2001 From: markmental Date: Sat, 28 Mar 2026 01:40:11 -0400 Subject: [PATCH] Theme tweaks --- src/app.c | 40 ++++ src/app.h | 3 + src/app.o | Bin 11424 -> 14248 bytes src/theme.h | 523 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ui.c | 330 ++++++++++++++++++++++----------- src/ui.h | 8 + src/ui.o | Bin 26712 -> 31608 bytes 7 files changed, 794 insertions(+), 110 deletions(-) diff --git a/src/app.c b/src/app.c index b355fdd..bdd1957 100644 --- a/src/app.c +++ b/src/app.c @@ -162,6 +162,28 @@ static void handle_event(App *app, const SDL_Event *event) { return; } + if (app->theme_picker_open) { + switch (event->key.keysym.sym) { + case SDLK_ESCAPE: + case SDLK_b: + app->theme_picker_open = 0; + return; + case SDLK_UP: + app->theme_picker_selection = (app->theme_picker_selection + GUIDE_THEME_COUNT - 1) % GUIDE_THEME_COUNT; + return; + case SDLK_DOWN: + app->theme_picker_selection = (app->theme_picker_selection + 1) % GUIDE_THEME_COUNT; + return; + case SDLK_RETURN: + case SDLK_KP_ENTER: + app->theme_index = app->theme_picker_selection; + app->theme_picker_open = 0; + return; + default: + return; + } + } + switch (event->key.keysym.sym) { case SDLK_ESCAPE: if (app->mode == MODE_GUIDE) { @@ -176,6 +198,13 @@ static void handle_event(App *app, const SDL_Event *event) { case SDLK_f: toggle_fullscreen(app); break; + case SDLK_b: + if (app->mode == MODE_FULLSCREEN) { + app->mode = MODE_GUIDE; + } + app->theme_picker_open = !app->theme_picker_open; + app->theme_picker_selection = app->theme_index; + break; case SDLK_UP: tune_relative(app, -1); break; @@ -192,6 +221,7 @@ int app_init(App *app) { app->running = 1; app->mode = MODE_FULLSCREEN; app->last_blackout_state = 1; + app->theme_index = 0; configure_runtime_environment(); log_runtime_environment("startup-before-sdl"); @@ -302,6 +332,7 @@ void app_run(App *app) { app->texture_height, output_width, output_height, + &GUIDE_THEMES[app->theme_index], &app->fonts, &app->ui_cache, &app->channels, @@ -309,6 +340,15 @@ void app_run(App *app) { app->app_start_ticks, now_ticks, now_wall); + if (app->theme_picker_open) { + ui_render_theme_picker(app->renderer, + &app->fonts, + output_width, + output_height, + &GUIDE_THEMES[app->theme_index], + app->theme_index, + app->theme_picker_selection); + } } else { if (!in_blackout) { player_resume_audio(&app->player); diff --git a/src/app.h b/src/app.h index 9f0e269..b057ac9 100644 --- a/src/app.h +++ b/src/app.h @@ -17,6 +17,9 @@ typedef struct App { AppMode mode; int running; int is_fullscreen; + int theme_index; + int theme_picker_open; + int theme_picker_selection; int startup_handoff_active; int last_blackout_state; Uint32 startup_handoff_until; diff --git a/src/app.o b/src/app.o index c3becbd4e2de00fb6fbf49e86865312562a12b62..83a38e8c80642aa02bb1bd845d3164a2c709884d 100644 GIT binary patch literal 14248 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 literal 11424 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 Nzph / 2; for (int i = 0; i < rect->h; ++i) { SDL_Color from = i < split ? top : middle; @@ -115,23 +148,23 @@ static void fill_rect_alpha(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Co static void draw_panel_shadow(SDL_Renderer *renderer, const SDL_Rect *rect) { SDL_Rect shadow = {rect->x + 6, rect->y + 6, rect->w, rect->h}; - fill_rect_alpha(renderer, &shadow, COLOR_PANEL_SHADOW); + fill_rect_alpha(renderer, &shadow, color_with_alpha(COLOR_PANEL_SHADOW, 48)); } -static void draw_gloss_line(SDL_Renderer *renderer, const SDL_Rect *rect) { +static void draw_gloss_line(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color gloss_color) { SDL_Rect gloss = {rect->x + 4, rect->y + 1, SDL_max(rect->w - 8, 0), 2}; if (gloss.w > 0) { - fill_rect_alpha(renderer, &gloss, COLOR_GLOSS); + fill_rect_alpha(renderer, &gloss, gloss_color); } } -static void draw_panel_bevel(SDL_Renderer *renderer, const SDL_Rect *rect) { +static void draw_panel_bevel(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color gloss_color) { SDL_Rect top_white = {rect->x + 8, rect->y, SDL_max(rect->w - 16, 0), 1}; SDL_Rect top_black = {rect->x + 8, rect->y + 1, SDL_max(rect->w - 16, 0), 1}; if (top_white.w > 0) { - fill_rect_alpha(renderer, &top_white, (SDL_Color){255, 255, 255, 128}); - fill_rect_alpha(renderer, &top_black, (SDL_Color){0, 0, 0, 51}); + fill_rect_alpha(renderer, &top_white, color_with_alpha(gloss_color, 72)); + fill_rect_alpha(renderer, &top_black, (SDL_Color){0, 0, 0, 28}); } } @@ -142,37 +175,36 @@ static void stroke_rect_alpha(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_ SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); } -static void draw_selection_glow(SDL_Renderer *renderer, const SDL_Rect *rect) { +static void draw_selection_glow(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color edge) { SDL_Rect outer = *rect; SDL_Rect inner = {rect->x + 1, rect->y + 1, rect->w - 2, rect->h - 2}; - stroke_rect_alpha(renderer, &outer, (SDL_Color){0xff, 0xd7, 0x00, 120}); + stroke_rect_alpha(renderer, &outer, color_with_alpha(edge, 62)); if (inner.w > 0 && inner.h > 0) { - stroke_rect_alpha(renderer, &inner, (SDL_Color){0xff, 0xd7, 0x00, 70}); + stroke_rect_alpha(renderer, &inner, color_with_alpha(edge, 34)); } } -static void draw_rounded_top_panel(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color fill_color) { +static void draw_rounded_top_panel(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color fill_color, SDL_Color border_color, int radius) { SDL_Rect body; SDL_Rect top; - if (!rect || rect->w < 8 || rect->h < 8) { + if (!rect || rect->w < radius || rect->h < radius) { return; } - body = (SDL_Rect){rect->x, rect->y + 8, rect->w, rect->h - 8}; - top = (SDL_Rect){rect->x + 8, rect->y, rect->w - 16, 8}; + body = (SDL_Rect){rect->x, rect->y + radius, rect->w, rect->h - radius}; + top = (SDL_Rect){rect->x + radius, rect->y, rect->w - radius * 2, radius}; fill_rect(renderer, &body, fill_color); fill_rect(renderer, &top, fill_color); - fill_rect(renderer, &(SDL_Rect){rect->x + 4, rect->y + 2, rect->w - 8, 6}, fill_color); - fill_rect(renderer, &(SDL_Rect){rect->x + 2, rect->y + 4, rect->w - 4, 4}, fill_color); - fill_rect(renderer, &(SDL_Rect){rect->x + 1, rect->y + 6, rect->w - 2, 2}, fill_color); + fill_rect(renderer, &(SDL_Rect){rect->x + radius / 2, rect->y + 2, rect->w - radius, radius - 2}, fill_color); + fill_rect(renderer, &(SDL_Rect){rect->x + 2, rect->y + radius / 2, rect->w - 4, radius / 2}, fill_color); - set_draw_color(renderer, COLOR_BORDER_DARK); - SDL_RenderDrawLine(renderer, rect->x + 8, rect->y, rect->x + rect->w - 9, rect->y); - SDL_RenderDrawLine(renderer, rect->x + 4, rect->y + 2, rect->x + 5, rect->y + 1); - SDL_RenderDrawLine(renderer, rect->x + rect->w - 6, rect->y + 1, rect->x + rect->w - 5, rect->y + 2); - SDL_RenderDrawLine(renderer, rect->x + 1, rect->y + 6, rect->x + 1, rect->y + rect->h - 2); - SDL_RenderDrawLine(renderer, rect->x + rect->w - 2, rect->y + 6, rect->x + rect->w - 2, rect->y + rect->h - 2); + set_draw_color(renderer, border_color); + SDL_RenderDrawLine(renderer, rect->x + radius, rect->y, rect->x + rect->w - radius - 1, rect->y); + SDL_RenderDrawLine(renderer, rect->x + radius / 2, rect->y + 2, rect->x + radius / 2 + 1, rect->y + 1); + SDL_RenderDrawLine(renderer, rect->x + rect->w - radius / 2 - 2, rect->y + 1, rect->x + rect->w - radius / 2 - 1, rect->y + 2); + SDL_RenderDrawLine(renderer, rect->x + 1, rect->y + radius - 2, rect->x + 1, rect->y + rect->h - 2); + SDL_RenderDrawLine(renderer, rect->x + rect->w - 2, rect->y + radius - 2, rect->x + rect->w - 2, rect->y + rect->h - 2); SDL_RenderDrawLine(renderer, rect->x + 1, rect->y + rect->h - 1, rect->x + rect->w - 2, rect->y + rect->h - 1); } @@ -188,13 +220,17 @@ static void draw_beveled_bar(SDL_Renderer *renderer, } fill_three_stop_gradient(renderer, rect, top, mid, bottom); - SDL_SetRenderDrawColor(renderer, top_edge.r, top_edge.g, top_edge.b, 255); + top_edge = blend_color(top_edge, mid, 170); + bottom_edge = blend_color(bottom_edge, mid, 170); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, top_edge.r, top_edge.g, top_edge.b, 110); SDL_RenderDrawLine(renderer, rect->x, rect->y, rect->x + rect->w - 1, rect->y); - SDL_SetRenderDrawColor(renderer, bottom_edge.r, bottom_edge.g, bottom_edge.b, 255); + SDL_SetRenderDrawColor(renderer, bottom_edge.r, bottom_edge.g, bottom_edge.b, 110); SDL_RenderDrawLine(renderer, rect->x, rect->y + rect->h - 1, rect->x + rect->w - 1, rect->y + rect->h - 1); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); } -static void draw_pill_button(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color fill, SDL_Color border) { +static void draw_pill_button(SDL_Renderer *renderer, const GuideTheme *theme, const SDL_Rect *rect, SDL_Color fill, SDL_Color border) { SDL_Rect shadow; if (!rect || rect->w < 10 || rect->h < 10) { @@ -202,8 +238,8 @@ static void draw_pill_button(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_C } shadow = (SDL_Rect){rect->x + 2, rect->y + 2, rect->w, rect->h}; - fill_rect_alpha(renderer, &shadow, COLOR_PILL_SHADOW); - draw_beveled_bar(renderer, rect, COLOR_PILL_LIGHT, fill, fill, COLOR_GLOSS, border); + fill_rect_alpha(renderer, &shadow, theme->pill_shadow); + draw_beveled_bar(renderer, rect, theme->pill_light, fill, fill, theme->gloss, border); set_draw_color(renderer, border); SDL_RenderDrawLine(renderer, rect->x + 4, rect->y, rect->x + rect->w - 5, rect->y); SDL_RenderDrawLine(renderer, rect->x + 4, rect->y + rect->h - 1, rect->x + rect->w - 5, rect->y + rect->h - 1); @@ -325,58 +361,63 @@ static void format_clock_label(char *buffer, size_t buffer_size, time_t now, int strftime(buffer, buffer_size, "%I:%M %p", &local_time); } -static void draw_timeline_header_cached(SDL_Renderer *renderer, const UiCache *cache, SDL_Rect rect) { +static void draw_timeline_header_cached(SDL_Renderer *renderer, const UiCache *cache, const GuideTheme *theme, SDL_Rect rect) { int segments = 4; draw_beveled_bar(renderer, &rect, - COLOR_RIBBON_TOP, - (SDL_Color){0x36, 0x2d, 0x83, 0xff}, - COLOR_RIBBON_BOTTOM, - COLOR_GLOSS, - COLOR_BORDER_DARK); + theme->ribbon_top, + theme->ribbon_mid, + theme->ribbon_bottom, + theme->gloss, + theme->panel_border); for (int i = 0; i < segments; ++i) { int x = rect.x + (rect.w * i) / segments; int centered_x = x - cache->timeline_labels[i].width / 2; draw_cached_text(renderer, &cache->timeline_labels[i], centered_x, rect.y + 10); - set_draw_color(renderer, COLOR_GRID_LINE); + set_draw_color(renderer, theme->grid_line); SDL_RenderDrawLine(renderer, x, rect.y + rect.h - 2, x, rect.y + rect.h + 5 * 76); } } static void draw_status_bar(SDL_Renderer *renderer, TTF_Font *font, + const GuideTheme *theme, const Channel *selected_channel, const SDL_Rect *rect, time_t now_wall) { char clock_text[32]; char channel_text[160]; + SDL_Color text_color; if (!rect) { return; } + text_color = readable_text_color(theme->status_mid); + draw_beveled_bar(renderer, rect, - COLOR_BUTTON_BAR_TOP, - COLOR_HEADER_SILVER, - COLOR_BUTTON_BAR_BOTTOM, - COLOR_GLOSS, - COLOR_BORDER_DARK); + 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, 36), + theme->panel_border); format_time_compact(clock_text, sizeof(clock_text), now_wall); - draw_text_clipped(renderer, font, clock_text, rect, rect->x + 12, rect->y + 10, COLOR_PANEL_TEXT); - set_draw_color(renderer, COLOR_STATUS_DIVIDER); + draw_text_clipped(renderer, font, clock_text, rect, rect->x + 12, rect->y + 10, text_color); + set_draw_color(renderer, theme->status_divider); SDL_RenderDrawLine(renderer, rect->x + rect->w / 2, rect->y + 8, rect->x + rect->w / 2, rect->y + rect->h - 8); if (selected_channel) { snprintf(channel_text, sizeof(channel_text), "%s %d", selected_channel->name, selected_channel->number); - draw_text_clipped(renderer, font, channel_text, rect, rect->x + rect->w - 260, rect->y + 10, COLOR_PANEL_TEXT); + draw_text_clipped(renderer, font, channel_text, rect, rect->x + rect->w - 260, rect->y + 10, text_color); } } static void draw_info_panel(SDL_Renderer *renderer, const UiFonts *fonts, + const GuideTheme *theme, const Channel *selected_channel, const SDL_Rect *rect, Uint64 app_start_ticks, @@ -397,11 +438,11 @@ static void draw_info_panel(SDL_Renderer *renderer, } draw_panel_shadow(renderer, rect); - draw_rounded_top_panel(renderer, rect, COLOR_HEADER_SILVER); + draw_rounded_top_panel(renderer, rect, theme->panel_fill, theme->panel_border, theme->rounded_radius > 0 ? theme->rounded_radius : 8); accent = (SDL_Rect){rect->x + 1, rect->y + 1, rect->w - 2, 38}; - fill_rect(renderer, &accent, COLOR_HEADER_SILVER); - draw_panel_bevel(renderer, rect); - stroke_rect(renderer, rect, COLOR_BORDER_DARK); + fill_rect(renderer, &accent, theme->panel_fill); + 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); if (!program) { @@ -419,66 +460,73 @@ static void draw_info_panel(SDL_Renderer *renderer, selected_channel->description[0] != '\0' ? selected_channel->description : "Local programming lineup."); clip_rect = (SDL_Rect){rect->x + 16, rect->y + 12, rect->w - 32, rect->h - 24}; - draw_text_clipped(renderer, fonts->large, selected_channel->name, &clip_rect, rect->x + 18, rect->y + 44, COLOR_PANEL_TEXT); - draw_text_clipped(renderer, fonts->medium, program->program_title, &clip_rect, rect->x + 18, rect->y + 88, COLOR_PANEL_TEXT); - draw_text_clipped(renderer, fonts->small, time_range, &clip_rect, rect->x + 18, rect->y + 124, COLOR_PANEL_TEXT); - draw_text_clipped(renderer, fonts->small, description, &clip_rect, rect->x + 18, rect->y + 148, COLOR_PANEL_TEXT); + draw_text_clipped(renderer, fonts->large, selected_channel->name, &clip_rect, rect->x + 18, rect->y + 44, theme->panel_text); + draw_text_clipped(renderer, fonts->medium, program->program_title, &clip_rect, rect->x + 18, rect->y + 88, theme->panel_text); + draw_text_clipped(renderer, fonts->small, time_range, &clip_rect, rect->x + 18, rect->y + 124, theme->panel_text); + draw_text_clipped(renderer, fonts->small, description, &clip_rect, rect->x + 18, rect->y + 148, theme->panel_text); } -static void draw_grid_background(SDL_Renderer *renderer, const SDL_Rect *grid_rect, int row_height, double pixels_per_minute) { +static void draw_grid_background(SDL_Renderer *renderer, const GuideTheme *theme, const SDL_Rect *grid_rect, int row_height, double pixels_per_minute) { fill_three_stop_gradient(renderer, grid_rect, - (SDL_Color){0x34, 0x26, 0x88, 0xff}, - (SDL_Color){0x1b, 0x2f, 0x8f, 0xff}, - (SDL_Color){0x00, 0x11, 0x33, 0xff}); + theme->background_top, + theme->background_mid, + theme->background_bottom); for (int minute = 0; minute <= 90; minute += 30) { int x = GUIDE_X_START + (int) (minute * pixels_per_minute); - set_draw_color(renderer, COLOR_GRID_LINE); + set_draw_color(renderer, theme->grid_line); SDL_RenderDrawLine(renderer, x, grid_rect->y, x, grid_rect->y + grid_rect->h); } for (int row = 0; row <= GUIDE_VISIBLE_ROWS; ++row) { int y = grid_rect->y + row * row_height; - set_draw_color(renderer, COLOR_ROW_LINE_HI); + set_draw_color(renderer, theme->row_line_hi); SDL_RenderDrawLine(renderer, grid_rect->x, y, grid_rect->x + grid_rect->w, y); if (y + row_height - 1 <= grid_rect->y + grid_rect->h) { - set_draw_color(renderer, COLOR_ROW_LINE_LO); + set_draw_color(renderer, theme->row_line_lo); SDL_RenderDrawLine(renderer, grid_rect->x, y + row_height - 1, grid_rect->x + grid_rect->w, y + row_height - 1); } } } -static void draw_footer_legend(SDL_Renderer *renderer, const UiCache *cache, int window_width, int window_height) { +static void draw_footer_legend(SDL_Renderer *renderer, + const UiFonts *fonts, + const GuideTheme *theme, + int window_width, + int window_height) { SDL_Rect footer = {0, window_height - 54, window_width, 54}; SDL_Rect chip = {window_width / 2 - 180, window_height - 38, 34, 20}; + SDL_Color footer_text = readable_text_color(theme->footer_mid); - fill_three_stop_gradient(renderer, &footer, COLOR_BUTTON_BAR_TOP, COLOR_HEADER_SILVER, COLOR_BUTTON_BAR_BOTTOM); - draw_gloss_line(renderer, &footer); - stroke_rect(renderer, &footer, COLOR_BORDER_DARK); + fill_three_stop_gradient(renderer, + &footer, + blend_color(theme->footer_top, theme->footer_mid, 240), + theme->footer_mid, + blend_color(theme->footer_bottom, theme->footer_mid, 240)); + draw_gloss_line(renderer, &footer, color_with_alpha(theme->gloss, 20)); + stroke_rect(renderer, &footer, theme->panel_border); - draw_pill_button(renderer, &chip, COLOR_HIGHLIGHT_YELLOW, COLOR_BORDER_DARK); - draw_cached_text(renderer, &cache->footer_a, chip.x + 11, chip.y + 1); - draw_cached_text(renderer, &cache->footer_time, chip.x + 42, chip.y - 1); + draw_pill_button(renderer, theme, &chip, theme->panel_fill, theme->panel_border); + draw_text_clipped(renderer, fonts->medium, "A", &footer, chip.x + 11, chip.y + 1, footer_text); + draw_text_clipped(renderer, fonts->small, "TIME", &footer, chip.x + 42, chip.y - 1, footer_text); chip.x += 144; - draw_pill_button(renderer, &chip, COLOR_BLOCK_UNSELECTED, COLOR_BORDER_DARK); - draw_cached_text(renderer, &cache->footer_b, chip.x + 11, chip.y + 1); - draw_cached_text(renderer, &cache->footer_theme, chip.x + 42, chip.y - 1); + draw_pill_button(renderer, theme, &chip, theme->block_mid, theme->panel_border); + draw_text_clipped(renderer, fonts->medium, "B", &footer, chip.x + 11, chip.y + 1, footer_text); + draw_text_clipped(renderer, fonts->small, "THEME", &footer, chip.x + 42, chip.y - 1, footer_text); chip.x += 150; - draw_pill_button(renderer, &chip, COLOR_HINT_RED, COLOR_BORDER_DARK); - draw_cached_text(renderer, &cache->footer_c, chip.x + 11, chip.y + 1); - draw_cached_text(renderer, &cache->footer_title, chip.x + 42, chip.y - 1); + draw_pill_button(renderer, theme, &chip, theme->row_active_mid, theme->panel_border); + draw_text_clipped(renderer, fonts->medium, "C", &footer, chip.x + 11, chip.y + 1, footer_text); + draw_text_clipped(renderer, fonts->small, "TITLE", &footer, chip.x + 42, chip.y - 1, footer_text); } -static void draw_scanline_overlay(SDL_Renderer *renderer, int width, int height) { - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 26); - for (int y = 0; y < height; y += 2) { - SDL_RenderDrawLine(renderer, 0, y, width, y); - } - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); +static void draw_scanline_overlay(SDL_Renderer *renderer, int width, int height, const GuideTheme *theme) { + (void) renderer; + (void) width; + (void) height; + (void) theme; } void ui_render_no_media(SDL_Renderer *renderer, const UiCache *cache, int window_width, int window_height) { @@ -506,6 +554,7 @@ void ui_render_guide(SDL_Renderer *renderer, int texture_height, int window_width, int window_height, + const GuideTheme *theme, const UiFonts *fonts, UiCache *cache, const ChannelList *channels, @@ -535,26 +584,26 @@ void ui_render_guide(SDL_Renderer *renderer, fill_three_stop_gradient(renderer, &full, - (SDL_Color){0x2a, 0x2e, 0x8f, 0xff}, - COLOR_GUIDE_TOP, - COLOR_GUIDE_BOTTOM); - draw_info_panel(renderer, fonts, selected_channel, &info_panel, app_start_ticks, now_ticks, now_wall); + 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_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, selected_channel, &status_bar, now_wall); + draw_status_bar(renderer, fonts->medium, theme, selected_channel, &status_bar, now_wall); if (cache->timeline_label_slot != now_wall / 60) { char label[32]; for (int i = 0; i < 4; ++i) { format_clock_label(label, sizeof(label), now_wall, (int) ((TIMELINE_VISIBLE_SECONDS / 60.0 / 4) * i)); text_texture_destroy(&cache->timeline_labels[i]); - text_texture_init(&cache->timeline_labels[i], renderer, fonts->small, label, COLOR_TEXT_LIGHT); + text_texture_init(&cache->timeline_labels[i], renderer, fonts->small, label, theme->ribbon_text); } cache->timeline_label_slot = now_wall / 60; } - draw_timeline_header_cached(renderer, cache, header_row); - draw_grid_background(renderer, &grid, row_height, pixels_per_minute); + draw_timeline_header_cached(renderer, cache, theme, header_row); + draw_grid_background(renderer, theme, &grid, row_height, pixels_per_minute); if (start_index < 0) { start_index = 0; @@ -574,19 +623,19 @@ void ui_render_guide(SDL_Renderer *renderer, draw_beveled_bar(renderer, &row_rect, - is_selected ? COLOR_ROW_ACTIVE_TOP : COLOR_ROW_TOP, - is_selected ? COLOR_ROW_ACTIVE_MID : COLOR_ROW_MID, - is_selected ? COLOR_ROW_ACTIVE_BOTTOM : COLOR_ROW_BOTTOM, - COLOR_GLOSS, - COLOR_BORDER_DARK); + is_selected ? theme->row_active_top : theme->row_top, + is_selected ? theme->row_active_mid : theme->row_mid, + is_selected ? theme->row_active_bottom : theme->row_bottom, + theme->gloss, + theme->panel_border); fill_rect_alpha(renderer, &inset, (SDL_Color){255, 255, 255, is_selected ? 12 : 6}); draw_beveled_bar(renderer, &sidebar, - is_selected ? COLOR_ROW_ACTIVE_TOP : COLOR_ROW_TOP, - is_selected ? COLOR_ROW_ACTIVE_MID : COLOR_ROW_MID, - is_selected ? COLOR_ROW_ACTIVE_BOTTOM : COLOR_ROW_BOTTOM, - COLOR_GLOSS, - COLOR_BORDER_DARK); + is_selected ? theme->row_active_top : theme->row_top, + is_selected ? theme->row_active_mid : theme->row_mid, + is_selected ? theme->row_active_bottom : theme->row_bottom, + theme->gloss, + theme->panel_border); if (!channels || channel_index >= channels->count) { continue; @@ -616,26 +665,36 @@ void ui_render_guide(SDL_Renderer *renderer, title_rect = (SDL_Rect){block.x + 8, block.y + 8, block.w - 16, block.h - 16}; if (is_selected) { - draw_text_clipped(renderer, fonts->medium, channel->name, &sidebar, 20, row_rect.y + 12, COLOR_ACTIVE_TEXT); + draw_text_clipped(renderer, fonts->medium, channel->name, &sidebar, 20, row_rect.y + 12, theme->row_active_text); { char number[16]; snprintf(number, sizeof(number), "%d", channel->number); - draw_text_clipped(renderer, fonts->medium, number, &sidebar, 176, row_rect.y + 12, COLOR_ACTIVE_TEXT); + draw_text_clipped(renderer, fonts->medium, number, &sidebar, 176, row_rect.y + 12, theme->row_active_text); } } else { - draw_cached_text(renderer, &cache->channels[channel_index].name_medium, 20, row_rect.y + 12); - draw_cached_text(renderer, &cache->channels[channel_index].number_medium, 176, row_rect.y + 12); + draw_text_clipped(renderer, fonts->medium, channel->name, &sidebar, 20, row_rect.y + 12, theme->row_text); + { + char number[16]; + snprintf(number, sizeof(number), "%d", channel->number); + draw_text_clipped(renderer, fonts->medium, number, &sidebar, 176, row_rect.y + 12, theme->row_text); + } } - draw_text_clipped(renderer, fonts->small, program->file_name, &sidebar, 20, row_rect.y + 38, COLOR_PALE_BLUE); + draw_text_clipped(renderer, + fonts->small, + program->file_name, + &sidebar, + 20, + row_rect.y + 38, + secondary_text_color(theme->row_text, is_selected ? theme->row_active_mid : theme->row_mid)); SDL_RenderSetClipRect(renderer, &clip); draw_beveled_bar(renderer, &block, - is_selected ? COLOR_BLOCK_ACTIVE_TOP : COLOR_BLOCK_TOP, - is_selected ? COLOR_BLOCK_ACTIVE_MID : COLOR_BLOCK_MID, - is_selected ? COLOR_BLOCK_ACTIVE_BOTTOM : COLOR_BLOCK_BOTTOM, - is_selected ? COLOR_SELECTION_EDGE : COLOR_GLOSS, - COLOR_BORDER_DARK); + 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, @@ -647,19 +706,70 @@ void ui_render_guide(SDL_Renderer *renderer, &title_rect, title_rect.x, title_rect.y, - is_selected ? COLOR_TEXT_DARK : COLOR_TEXT_LIGHT); + is_selected ? theme->block_active_text : theme->block_text); SDL_RenderSetClipRect(renderer, NULL); } } if (selected_channel && active_channel >= 0 && start_index <= active_channel && active_channel < start_index + GUIDE_VISIBLE_ROWS) { SDL_Rect highlight = {0, grid.y + (active_channel - start_index) * row_height, window_width, row_height}; - draw_selection_glow(renderer, &highlight); - draw_selection_glow(renderer, &(SDL_Rect){guide_x_start, highlight.y + (int) (6 * scale_y), timeline_w, row_height - (int) (12 * scale_y)}); + draw_selection_glow(renderer, &highlight, theme->selection_edge); + draw_selection_glow(renderer, &(SDL_Rect){guide_x_start, highlight.y + (int) (6 * scale_y), timeline_w, row_height - (int) (12 * scale_y)}, theme->selection_edge); } - draw_footer_legend(renderer, cache, window_width, window_height); - draw_scanline_overlay(renderer, window_width, window_height); + draw_footer_legend(renderer, fonts, theme, window_width, window_height); + draw_scanline_overlay(renderer, window_width, window_height, theme); +} + +void ui_render_theme_picker(SDL_Renderer *renderer, + const UiFonts *fonts, + int window_width, + int window_height, + const GuideTheme *active_theme, + int current_theme_index, + int selected_theme_index) { + SDL_Rect overlay = {0, 0, window_width, window_height}; + SDL_Rect modal = {window_width / 2 - 250, window_height / 2 - 180, 500, 360}; + SDL_Rect title_bar = {modal.x, modal.y, modal.w, 38}; + + (void) current_theme_index; + fill_rect_alpha(renderer, &overlay, (SDL_Color){0, 0, 0, 120}); + draw_panel_shadow(renderer, &modal); + draw_rounded_top_panel(renderer, &modal, active_theme->panel_fill, active_theme->panel_border, active_theme->rounded_radius > 0 ? active_theme->rounded_radius : 8); + fill_rect(renderer, &(SDL_Rect){modal.x, modal.y + 38, modal.w, modal.h - 38}, active_theme->footer_mid); + draw_beveled_bar(renderer, &title_bar, active_theme->ribbon_top, active_theme->ribbon_mid, active_theme->ribbon_bottom, active_theme->gloss, active_theme->panel_border); + draw_text_clipped(renderer, fonts->medium, "THEME SELECT", &modal, modal.x + 16, modal.y + 10, active_theme->ribbon_text); + + for (int i = 0; i < GUIDE_THEME_COUNT; ++i) { + SDL_Rect item = {modal.x + 18, modal.y + 52 + i * 28, modal.w - 36, 24}; + SDL_Rect swatch = {modal.x + modal.w - 118, item.y + 4, 92, 14}; + char label[96]; + const GuideTheme *theme = &GUIDE_THEMES[i]; + + if (i == selected_theme_index) { + draw_beveled_bar(renderer, &item, theme->row_active_top, theme->row_active_mid, theme->row_active_bottom, theme->gloss, theme->panel_border); + draw_selection_glow(renderer, &item, theme->selection_edge); + } + + snprintf(label, sizeof(label), "%c %s", i == selected_theme_index ? '>' : ' ', theme->name); + draw_text_clipped(renderer, + fonts->small, + label, + &item, + item.x + 8, + item.y + 4, + i == selected_theme_index ? theme->row_active_text : active_theme->panel_text); + fill_three_stop_gradient(renderer, &swatch, theme->background_top, theme->background_mid, theme->background_bottom); + stroke_rect(renderer, &swatch, theme->panel_border); + } + + draw_text_clipped(renderer, + fonts->small, + "ENTER APPLY ESC CANCEL B CLOSE", + &modal, + modal.x + 18, + modal.y + modal.h - 28, + active_theme->panel_text); } int ui_cache_init(UiCache *cache, SDL_Renderer *renderer, const UiFonts *fonts, const ChannelList *channels) { diff --git a/src/ui.h b/src/ui.h index 02fc9ac..36af144 100644 --- a/src/ui.h +++ b/src/ui.h @@ -58,6 +58,7 @@ void ui_render_guide(SDL_Renderer *renderer, int texture_height, int window_width, int window_height, + const GuideTheme *theme, const UiFonts *fonts, UiCache *cache, const ChannelList *channels, @@ -65,6 +66,13 @@ void ui_render_guide(SDL_Renderer *renderer, Uint64 app_start_ticks, Uint64 now_ticks, time_t now_wall); +void ui_render_theme_picker(SDL_Renderer *renderer, + const UiFonts *fonts, + int window_width, + int window_height, + const GuideTheme *active_theme, + int current_theme_index, + int selected_theme_index); void ui_render_no_media(SDL_Renderer *renderer, const UiCache *cache, int window_width, int window_height); int ui_load_fonts(UiFonts *fonts); void ui_destroy_fonts(UiFonts *fonts); diff --git a/src/ui.o b/src/ui.o index a98777df2f47967ac3f560b48735a2fc36715ee2..bff4a1d3f85e7ba684327937f9eaab7a8933b7e6 100644 GIT binary patch literal 31608 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 STzO@MRp`%BS$d5u|9=4BZ-6QQ literal 26712 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

2?+UK+|EX}5saWOn zsDdw59D`;3}V(f~$PKD9+t9p7fW5ay*L^JV(J73!LOs<*!k2wcU_{tL=sr zT;;Pv!Bsy0rQoWbjHkdqBaZ4Mr%HcK3cO3f)%6lhf&W_y{0}Mcr&Hjsq`=Rn!1XM2 z2!Z;g%9)!2U!4M9ui%y7CFi|g!Bzf8Qs9mYNScqz<4%E>r@$Li;J;CDRnE(VU!A;O z<|??VZ`TQ&^!$I}k^Q|zp*Iygq|nn@UebRv1^xd~=;<$#CH-S5=uauQs^>V8vq1e) z7R`5S5_-qCD{R=V(B9|EZcuPl|7#Uo<+CFNeni1l{>Kzt)${ihT;*TwV&b#; znunyEuUiG4tPj7SO$&i=mCut3uFCU_f~)epsNgD}#g{SmOdeXYQl5ywll5e?f~)-h zL*Y}P@c9&Nq6o=+E?00>-~0-G6Y5EMzOCTue)MyJr-4@8PoGfemn(dpRdAKhNd;Hw z&nfsV3LpND&+&CfSA$Yc-Hi+a^>-y6iGNzbRX$fJxJrM$z^PyJ6+V>;uIkTi3Ln*; zbSv}=6h7Z0X9XbxkE##b6kOG-9SW|_`_l@p@+l*y2Z7{Yh)0e?mB6W8RnGrZaMiv& zNRx^{^r}3ME4V7pAq7|IPbj!bpGnRK0?BzL9w}$Jz?0jpQE-({SmAS(!e^U8ugbGu z!Bsx5D15%8@R?1{4MMU!^A%j>vsA&=cJEMd)gFF71->%{emn(!DLE5DPL=<%6!>ox zT-Bfb3a-k3Si#l)zNX+RpOY!@DPK&;sq+7Xf~)*5QE-+2&jg-qf6B-yL7@4%6_3=b z7J(DJa21i#v~>zzguJAGP{D~li--|^r{KlNOZvkKPW041g*O!ZYUCyTg>zXk(|@9u z_+<)yje;*yaFu?Af?uo9->cw6FT=ko_;mnfyZs8T^53Q4*DLg63a;``C#MI2#`(*5 zB>&45T;*S?;2wqkdje0M$D;~8@sZ=~orerU^8DVNgiCq$DL74$#E&Srq2R{^PVK4o zGm|!51lg|S^Hl{`?eJX!Pv-M`gMBARUcwK`tDPSDf%PsJnK zm*amMFlt{cJEV9xA=*!#Zz;E=YeRyt3nd_9a>5Zj>^Jcv`N{Y$6irs&BkB((sT<(KidQ7+Resf(QdNkTI1!=NE7dHiI3_OD$ke5BkGdJu`p z=5Jjcr;zrU#>aJ+u^0a(yaJ);+4>^3gB;9d}`OdG4cQ VMSLf#e`F1>@mpC@#L46L{{To{q7VQ8