From 4abcfa473f73ee4e9cdb9d7b4cc46e6bed98adea Mon Sep 17 00:00:00 2001 From: NeilClack Date: Thu, 13 Aug 2026 14:34:49 -0500 Subject: [PATCH] Change menu text from gray to white --- src/home.cpp | 194 ++++++++++++++++++++++++++++---------------- src/settings.cpp | 206 +++++++++++++++++++++++++++++------------------ 2 files changed, 249 insertions(+), 151 deletions(-) diff --git a/src/home.cpp b/src/home.cpp index 4713bfe..d490d5a 100644 --- a/src/home.cpp +++ b/src/home.cpp @@ -16,7 +16,7 @@ #include #ifndef APP_VERSION -#define APP_VERSION "unknown" +#define APP_VERSION "dev" #endif static TextLine renderText(SDL_Renderer *renderer, TTF_Font *font, const char *text, SDL_Color color) @@ -47,12 +47,10 @@ void Home::onPush(AppState &state) refreshStatus(); state.licenseTracker.refresh(); - state.keybinds.bind(SDLK_UP, "menu_up", [this]() { - state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; - }); - state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() { - state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; - }); + state.keybinds.bind(SDLK_UP, "menu_up", [this]() + { state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; }); + state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() + { state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; }); } void Home::onResume(AppState &state) @@ -63,12 +61,10 @@ void Home::onResume(AppState &state) refreshStatus(); state.licenseTracker.refresh(); - state.keybinds.bind(SDLK_UP, "menu_up", [this]() { - state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; - }); - state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() { - state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; - }); + state.keybinds.bind(SDLK_UP, "menu_up", [this]() + { state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; }); + state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() + { state_->currentMenuItem = (state_->currentMenuItem + 1) % 2; }); } void Home::onPause(AppState &state) @@ -85,15 +81,22 @@ void Home::onPop(AppState &state) void Home::handleEvent(const SDL_Event &event) { - if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_RETURN) { - if (state_->currentMenuItem == 0) { + if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_RETURN) + { + if (state_->currentMenuItem == 0) + { // Only a confirmed-valid license unlocks the scroller. - if (state_->licenseTracker.isValid()) { + if (state_->licenseTracker.isValid()) + { state_->pages.push(*state_, std::make_unique()); - } else { + } + else + { state_->pages.push(*state_, std::make_unique()); } - } else if (state_->currentMenuItem == 1) { + } + else if (state_->currentMenuItem == 1) + { state_->pages.replace(*state_, std::make_unique()); } } @@ -102,7 +105,8 @@ void Home::handleEvent(const SDL_Event &event) void Home::update(float dt) { internetRefreshTimer_ -= dt; - if (internetRefreshTimer_ <= 0.0f) { + if (internetRefreshTimer_ <= 0.0f) + { internetRefreshTimer_ = 5.0f; refreshStatus(); } @@ -133,7 +137,8 @@ void Home::render(SDL_Renderer *renderer) SDL_FRect overlay{0, 0, fw, fh}; SDL_RenderFillRect(renderer, &overlay); - if (!title_.texture) return; + if (!title_.texture) + return; float titleX = (fw - title_.width) / 2.0f; float titleY = fh / 3.0f - 60.0f; @@ -194,30 +199,31 @@ void Home::render(SDL_Renderer *renderer) std::string licenseValue; SDL_Color licenseColor = footerColor; bool licenseBold = false; - switch (licenseStatus) { - case radiantwave::license::Status::Valid: - licenseValue = "OK"; - licenseColor = okGreen; - break; - case radiantwave::license::Status::Invalid: - licenseValue = "Invalid"; - licenseColor = badRed; - licenseBold = true; - break; - case radiantwave::license::Status::Checking: - licenseValue = "Checking..."; - break; - case radiantwave::license::Status::Unknown: - licenseValue = "Unknown"; - break; + switch (licenseStatus) + { + case radiantwave::license::Status::Valid: + licenseValue = "OK"; + licenseColor = okGreen; + break; + case radiantwave::license::Status::Invalid: + licenseValue = "Invalid"; + licenseColor = badRed; + licenseBold = true; + break; + case radiantwave::license::Status::Checking: + licenseValue = "Checking..."; + break; + case radiantwave::license::Status::Unknown: + licenseValue = "Unknown"; + break; } int subscriptionLevelId = state_ - ? radiantwave::license::getStoredSubscriptionLevelId(state_->db) - : 0; + ? radiantwave::license::getStoredSubscriptionLevelId(state_->db) + : 0; std::string subscriptionValue = subscriptionLevelId > 0 - ? radiantwave::license::subscriptionLevelName(subscriptionLevelId) - : std::string("Not set"); + ? radiantwave::license::subscriptionLevelName(subscriptionLevelId) + : std::string("Not set"); time_t now = std::time(nullptr); std::vector names = { @@ -250,23 +256,32 @@ void Home::render(SDL_Renderer *renderer) valueColors[1] = licenseColor; valueBold[1] = licenseBold; - if (footerNames_.size() != names.size()) footerNames_.resize(names.size()); - if (footerValues_.size() != values.size()) footerValues_.resize(values.size()); - for (size_t i = 0; i < names.size(); ++i) { + if (footerNames_.size() != names.size()) + footerNames_.resize(names.size()); + if (footerValues_.size() != values.size()) + footerValues_.resize(values.size()); + for (size_t i = 0; i < names.size(); ++i) + { footerNames_[i].ensure(renderer, footerFont_, names[i], footerColor); } - for (size_t i = 0; i < values.size(); ++i) { - if (valueBold[i]) TTF_SetFontStyle(footerFont_, TTF_STYLE_BOLD); + for (size_t i = 0; i < values.size(); ++i) + { + if (valueBold[i]) + TTF_SetFontStyle(footerFont_, TTF_STYLE_BOLD); footerValues_[i].ensure(renderer, footerFont_, values[i], valueColors[i], - valueBold[i] ? TTF_STYLE_BOLD : TTF_STYLE_NORMAL); - if (valueBold[i]) TTF_SetFontStyle(footerFont_, TTF_STYLE_NORMAL); + valueBold[i] ? TTF_STYLE_BOLD : TTF_STYLE_NORMAL); + if (valueBold[i]) + TTF_SetFontStyle(footerFont_, TTF_STYLE_NORMAL); } float maxNameW = 0.0f; float maxValueW = 0.0f; - for (size_t i = 0; i < footerNames_.size(); ++i) { - if (footerNames_[i].width > maxNameW) maxNameW = footerNames_[i].width; - if (footerValues_[i].width > maxValueW) maxValueW = footerValues_[i].width; + for (size_t i = 0; i < footerNames_.size(); ++i) + { + if (footerNames_[i].width > maxNameW) + maxNameW = footerNames_[i].width; + if (footerValues_[i].width > maxValueW) + maxValueW = footerValues_[i].width; } CachedText fourSpaces; @@ -280,14 +295,16 @@ void Home::render(SDL_Renderer *renderer) float lineY = fh - margin; const float lineGap = 6.0f; - for (size_t i = footerNames_.size(); i-- > 0; ) + for (size_t i = footerNames_.size(); i-- > 0;) { float h = std::max(footerNames_[i].height, footerValues_[i].height); - if (footerNames_[i].texture) { + if (footerNames_[i].texture) + { SDL_FRect dst{rectLeft, lineY - h, footerNames_[i].width, footerNames_[i].height}; SDL_RenderTexture(renderer, footerNames_[i].texture, nullptr, &dst); } - if (footerValues_[i].texture) { + if (footerValues_[i].texture) + { SDL_FRect dst{rectRight - footerValues_[i].width, lineY - h, footerValues_[i].width, footerValues_[i].height}; SDL_RenderTexture(renderer, footerValues_[i].texture, nullptr, &dst); } @@ -309,7 +326,8 @@ void Home::createTextures(AppState &state) TextLine textWidthRef = renderText(state.renderer, font, "Radiant Wave", white); float targetWidth = textWidthRef.width * 1.5f; - if (textWidthRef.texture) SDL_DestroyTexture(textWidthRef.texture); + if (textWidthRef.texture) + SDL_DestroyTexture(textWidthRef.texture); TTF_CloseFont(font); @@ -338,9 +356,8 @@ void Home::createTextures(AppState &state) return; } - SDL_Color gray = {180, 180, 180, 255}; - play_ = renderText(state.renderer, font, "Play", gray); - settings_ = renderText(state.renderer, font, "Settings", gray); + play_ = renderText(state.renderer, font, "Play", white); + settings_ = renderText(state.renderer, font, "Settings", white); TTF_CloseFont(font); @@ -356,16 +373,26 @@ void Home::createTextures(AppState &state) footerFont_ = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 20); const std::vector footerNames = { - "Version:", "License:", "Key:", "Email:", "Subscription:", "WiFi:", - "Internet:", "Audio:", "Date:", "Time:", + "Version:", + "License:", + "Key:", + "Email:", + "Subscription:", + "WiFi:", + "Internet:", + "Audio:", + "Date:", + "Time:", }; footerNames_.clear(); footerValues_.clear(); footerNames_.resize(footerNames.size()); footerValues_.resize(footerNames.size()); SDL_Color footerColor = {200, 200, 200, 255}; - if (footerFont_) { - for (size_t i = 0; i < footerNames.size(); ++i) { + if (footerFont_) + { + for (size_t i = 0; i < footerNames.size(); ++i) + { footerNames_[i].ensure(state.renderer, footerFont_, footerNames[i], footerColor); } } @@ -373,20 +400,43 @@ void Home::createTextures(AppState &state) void Home::destroyTextures() { - if (bg_.texture) { SDL_DestroyTexture(bg_.texture); bg_.texture = nullptr; } - if (title_.texture) { SDL_DestroyTexture(title_.texture); title_.texture = nullptr; } - if (play_.texture) { SDL_DestroyTexture(play_.texture); play_.texture = nullptr; } - if (settings_.texture) { SDL_DestroyTexture(settings_.texture); settings_.texture = nullptr; } - for (auto& t : footerNames_) t.destroy(); - for (auto& t : footerValues_) t.destroy(); + if (bg_.texture) + { + SDL_DestroyTexture(bg_.texture); + bg_.texture = nullptr; + } + if (title_.texture) + { + SDL_DestroyTexture(title_.texture); + title_.texture = nullptr; + } + if (play_.texture) + { + SDL_DestroyTexture(play_.texture); + play_.texture = nullptr; + } + if (settings_.texture) + { + SDL_DestroyTexture(settings_.texture); + settings_.texture = nullptr; + } + for (auto &t : footerNames_) + t.destroy(); + for (auto &t : footerValues_) + t.destroy(); footerNames_.clear(); footerValues_.clear(); - if (footerFont_) { TTF_CloseFont(footerFont_); footerFont_ = nullptr; } + if (footerFont_) + { + TTF_CloseFont(footerFont_); + footerFont_ = nullptr; + } } void Home::refreshStatus() { - if (!state_) return; + if (!state_) + return; email_ = state_->db.getKV(radiantwave::db::KV_EMAIL_ADDRESS); license_ = state_->db.getKV(radiantwave::db::KV_LICENSE_KEY); dateFormat_ = state_->db.getKV("date_format", radiantwave::datetime::DEFAULT_DATE_FORMAT); @@ -401,7 +451,8 @@ void Home::syncProclamationsIfEmpty(AppState &state) // Proclamation options. Skipped once the database has content so a // blocking sync never runs on every Home push. The API call is also // skipped when the database is closed (fallback path in provisioning). - if (state.db.isOpen() && state.db.getActiveProclamations().empty()) { + if (state.db.isOpen() && state.db.getActiveProclamations().empty()) + { // TODO(portal #4/#5): once the portal exposes color palettes, sync them // alongside proclamations here (sync::syncColorPalettesFromApi) so Play's // scroller has portal colors from the very first run. @@ -411,7 +462,8 @@ void Home::syncProclamationsIfEmpty(AppState &state) std::string Home::audioStatus() const { - if (!state_) return "Idle"; + if (!state_) + return "Idle"; std::string status = state_->audioDownloader.statusString(); return status.empty() ? "Idle" : status; } diff --git a/src/settings.cpp b/src/settings.cpp index 293299f..b7cb3d1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -14,88 +14,109 @@ #include #include -namespace { +namespace +{ -constexpr int MENU_ITEM_COUNT = 9; -// 0 = WiFi Setup, 1 = Audio Options, 2 = Time Zone Setup, 3 = Proclamations, -// 4 = Email Address, 5 = License Key, 6 = Date Format, -// 7 = View System Logs, 8 = Back -constexpr const char* MENU_LABELS[MENU_ITEM_COUNT] = { - "WiFi Setup", - "Audio Options", - "Time Zone Setup", - "Proclamations", - "Email Address", - "License Key", - "Date Format", - "View System Logs", - "Back to Home", -}; + constexpr int MENU_ITEM_COUNT = 9; + // 0 = WiFi Setup, 1 = Audio Options, 2 = Time Zone Setup, 3 = Proclamations, + // 4 = Email Address, 5 = License Key, 6 = Date Format, + // 7 = View System Logs, 8 = Back + constexpr const char *MENU_LABELS[MENU_ITEM_COUNT] = { + "WiFi Setup", + "Audio Options", + "Time Zone Setup", + "Proclamations", + "Email Address", + "License Key", + "Date Format", + "View System Logs", + "Back to Home", + }; } // anonymous namespace -void Settings::onPush(AppState& state) +void Settings::onPush(AppState &state) { state_ = &state; TTF_Init(); createTextures(state); - state.keybinds.bind(SDLK_UP, "menu_up", [this]() { - selectedItem_ = (selectedItem_ - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT; - }); - state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() { - selectedItem_ = (selectedItem_ + 1) % MENU_ITEM_COUNT; - }); + state.keybinds.bind(SDLK_UP, "menu_up", [this]() + { selectedItem_ = (selectedItem_ - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT; }); + state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() + { selectedItem_ = (selectedItem_ + 1) % MENU_ITEM_COUNT; }); } -void Settings::onResume(AppState& state) +void Settings::onResume(AppState &state) { state_ = &state; createTextures(state); - state.keybinds.bind(SDLK_UP, "menu_up", [this]() { - selectedItem_ = (selectedItem_ - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT; - }); - state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() { - selectedItem_ = (selectedItem_ + 1) % MENU_ITEM_COUNT; - }); + state.keybinds.bind(SDLK_UP, "menu_up", [this]() + { selectedItem_ = (selectedItem_ - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT; }); + state.keybinds.bind(SDLK_DOWN, "menu_down", [this]() + { selectedItem_ = (selectedItem_ + 1) % MENU_ITEM_COUNT; }); } -void Settings::onPause(AppState& state) +void Settings::onPause(AppState &state) { state.keybinds.unbindAll(); destroyTextures(); } -void Settings::onPop(AppState& state) +void Settings::onPop(AppState &state) { destroyTextures(); TTF_Quit(); } -void Settings::handleEvent(const SDL_Event& event) +void Settings::handleEvent(const SDL_Event &event) { - if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_RETURN) { - switch (selectedItem_) { - case 0: state_->pages.push(*state_, std::make_unique()); break; - case 1: state_->pages.push(*state_, std::make_unique()); break; - case 2: state_->pages.push(*state_, std::make_unique()); break; - case 3: - // The Proclamation list is license-gated like Play. - if (state_->licenseTracker.isValid()) { - state_->pages.push(*state_, std::make_unique()); - } else { - state_->pages.push(*state_, std::make_unique()); - } - break; - case 4: state_->pages.push(*state_, std::make_unique()); break; - case 5: state_->pages.push(*state_, std::make_unique()); break; - case 6: state_->pages.push(*state_, std::make_unique()); break; - case 7: state_->pages.push(*state_, std::make_unique()); break; - case 8: state_->pages.replace(*state_, std::make_unique()); break; - default: break; + if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_RETURN) + { + switch (selectedItem_) + { + case 0: + state_->pages.push(*state_, std::make_unique()); + break; + case 1: + state_->pages.push(*state_, std::make_unique()); + break; + case 2: + state_->pages.push(*state_, std::make_unique()); + break; + case 3: + // The Proclamation list is license-gated like Play. + if (state_->licenseTracker.isValid()) + { + state_->pages.push(*state_, std::make_unique()); + } + else + { + state_->pages.push(*state_, std::make_unique()); + } + break; + case 4: + state_->pages.push(*state_, std::make_unique()); + break; + case 5: + state_->pages.push(*state_, std::make_unique()); + break; + case 6: + state_->pages.push(*state_, std::make_unique()); + break; + case 7: + state_->pages.push(*state_, std::make_unique()); + break; + case 8: + state_->pages.replace(*state_, std::make_unique()); + break; + default: + break; } - } else if (event.type == SDL_EVENT_KEY_DOWN && (event.key.key == SDLK_ESCAPE || event.key.key == SDLK_TAB)) { + } + else if (event.type == SDL_EVENT_KEY_DOWN && (event.key.key == SDLK_ESCAPE || event.key.key == SDLK_TAB)) + { state_->pages.replace(*state_, std::make_unique()); } } @@ -104,7 +125,7 @@ void Settings::update(float dt) { } -void Settings::render(SDL_Renderer* renderer) +void Settings::render(SDL_Renderer *renderer) { int winW, winH; SDL_GetWindowSize(SDL_GetRenderWindow(renderer), &winW, &winH); @@ -112,7 +133,8 @@ void Settings::render(SDL_Renderer* renderer) float fh = static_cast(winH); // 1. Logo Background Image - if (bgTexture_) { + if (bgTexture_) + { float scaleX = fw / bgWidth_; float scaleY = fh / bgHeight_; float scale = std::min(scaleX, scaleY); @@ -132,7 +154,8 @@ void Settings::render(SDL_Renderer* renderer) // 3. Title Text float titleY = 60.0f; - if (titleTexture_) { + if (titleTexture_) + { float x = (fw - titleWidth_) / 2.0f; SDL_FRect dst{x, titleY, titleWidth_, titleHeight_}; SDL_RenderTexture(renderer, titleTexture_, nullptr, &dst); @@ -140,7 +163,8 @@ void Settings::render(SDL_Renderer* renderer) // Compute bounding box for all menu items float maxWidth = 0.0f; - for (const auto& item : items_) { + for (const auto &item : items_) + { maxWidth = std::max(maxWidth, item.width); } float margin = 12.0f; // 12px vertical margin rule @@ -151,9 +175,11 @@ void Settings::render(SDL_Renderer* renderer) // Start menu list exactly 24 pixels below title text float currentY = titleY + titleHeight_ + 24.0f; - for (auto& item : items_) { + for (auto &item : items_) + { item.y = currentY; - if (item.texture) { + if (item.texture) + { SDL_FRect dst{sharedX, item.y, item.width, item.height}; SDL_RenderTexture(renderer, item.texture, nullptr, &dst); } @@ -161,9 +187,11 @@ void Settings::render(SDL_Renderer* renderer) } // 6px Underline for selected item occupying half of the 12px margin space - if (selectedItem_ >= 0 && selectedItem_ < static_cast(items_.size())) { - const auto& item = items_[selectedItem_]; - if (item.texture) { + if (selectedItem_ >= 0 && selectedItem_ < static_cast(items_.size())) + { + const auto &item = items_[selectedItem_]; + if (item.texture) + { SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_FRect line{sharedX, item.y + item.height + 2.0f, item.width, 6.0f}; SDL_RenderFillRect(renderer, &line); @@ -171,13 +199,14 @@ void Settings::render(SDL_Renderer* renderer) } } -void Settings::createTextures(AppState& state) +void Settings::createTextures(AppState &state) { destroyTextures(); // Background Image - SDL_Surface* bgSurface = IMG_Load("assets/images/RWT-Circular-Color-ForOnDark-NoText.png"); - if (bgSurface) { + SDL_Surface *bgSurface = IMG_Load("assets/images/RWT-Circular-Color-ForOnDark-NoText.png"); + if (bgSurface) + { bgTexture_ = SDL_CreateTextureFromSurface(state.renderer, bgSurface); bgWidth_ = static_cast(bgSurface->w); bgHeight_ = static_cast(bgSurface->h); @@ -185,12 +214,14 @@ void Settings::createTextures(AppState& state) SDL_SetTextureAlphaMod(bgTexture_, 204); } + SDL_Color white = {255, 255, 255, 255}; // Title Font - TTF_Font* fontLarge = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 64); - if (fontLarge) { - SDL_Color white = {255, 255, 255, 255}; - SDL_Surface* surface = TTF_RenderText_Blended(fontLarge, "Settings", 0, white); - if (surface) { + TTF_Font *fontLarge = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 64); + if (fontLarge) + { + SDL_Surface *surface = TTF_RenderText_Blended(fontLarge, "Settings", 0, white); + if (surface) + { titleTexture_ = SDL_CreateTextureFromSurface(state.renderer, surface); titleWidth_ = static_cast(surface->w); titleHeight_ = static_cast(surface->h); @@ -200,18 +231,20 @@ void Settings::createTextures(AppState& state) } // Item Font - TTF_Font* fontItem = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 36); - if (!fontItem) return; + TTF_Font *fontItem = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 36); + if (!fontItem) + return; - SDL_Color gray = {200, 200, 200, 255}; items_.reserve(MENU_ITEM_COUNT); - for (int i = 0; i < MENU_ITEM_COUNT; ++i) { + for (int i = 0; i < MENU_ITEM_COUNT; ++i) + { MenuItem item; item.label = MENU_LABELS[i]; - SDL_Surface* surface = TTF_RenderText_Blended(fontItem, MENU_LABELS[i], 0, gray); - if (surface) { + SDL_Surface *surface = TTF_RenderText_Blended(fontItem, MENU_LABELS[i], 0, white); + if (surface) + { item.texture = SDL_CreateTextureFromSurface(state.renderer, surface); item.width = static_cast(surface->w); item.height = static_cast(surface->h); @@ -225,10 +258,23 @@ void Settings::createTextures(AppState& state) void Settings::destroyTextures() { - if (bgTexture_) { SDL_DestroyTexture(bgTexture_); bgTexture_ = nullptr; } - if (titleTexture_) { SDL_DestroyTexture(titleTexture_); titleTexture_ = nullptr; } - for (auto& item : items_) { - if (item.texture) { SDL_DestroyTexture(item.texture); item.texture = nullptr; } + if (bgTexture_) + { + SDL_DestroyTexture(bgTexture_); + bgTexture_ = nullptr; + } + if (titleTexture_) + { + SDL_DestroyTexture(titleTexture_); + titleTexture_ = nullptr; + } + for (auto &item : items_) + { + if (item.texture) + { + SDL_DestroyTexture(item.texture); + item.texture = nullptr; + } } items_.clear(); }