#include "date_format_page.h" #include "app_state.h" #include "date_format.h" #include "logical_size.h" #include #include #include namespace { constexpr const char* DB_KEY = "date_format"; } // anonymous namespace void DateFormatPage::onPush(AppState& state) { state_ = &state; TTF_Init(); createFonts(); currentFormat_ = state.db.getKV(DB_KEY, radiantwave::datetime::DEFAULT_DATE_FORMAT); const auto options = radiantwave::datetime::getDateFormatOptions(); selectedIndex_ = 0; for (size_t i = 0; i < options.size(); ++i) { if (options[i].pattern == currentFormat_) { selectedIndex_ = static_cast(i); break; } } statusMessage_ = "Pick how the date should look"; state.keybinds.bind(SDLK_UP, "date_up", [this]() { const auto options = radiantwave::datetime::getDateFormatOptions(); selectedIndex_ = (selectedIndex_ - 1 + static_cast(options.size())) % static_cast(options.size()); }); state.keybinds.bind(SDLK_DOWN, "date_down", [this]() { const auto options = radiantwave::datetime::getDateFormatOptions(); selectedIndex_ = (selectedIndex_ + 1) % static_cast(options.size()); }); } void DateFormatPage::onResume(AppState& state) { state_ = &state; createFonts(); currentFormat_ = state.db.getKV(DB_KEY, radiantwave::datetime::DEFAULT_DATE_FORMAT); state.keybinds.bind(SDLK_UP, "date_up", [this]() { const auto options = radiantwave::datetime::getDateFormatOptions(); selectedIndex_ = (selectedIndex_ - 1 + static_cast(options.size())) % static_cast(options.size()); }); state.keybinds.bind(SDLK_DOWN, "date_down", [this]() { const auto options = radiantwave::datetime::getDateFormatOptions(); selectedIndex_ = (selectedIndex_ + 1) % static_cast(options.size()); }); } void DateFormatPage::onPause(AppState& state) { state.keybinds.unbindAll(); destroyFonts(); destroyTextures(); } void DateFormatPage::onPop(AppState& state) { destroyFonts(); destroyTextures(); TTF_Quit(); } void DateFormatPage::createFonts() { destroyFonts(); fontTitle_ = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 52); fontHeader_ = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 28); fontBody_ = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 32); fontSmall_ = TTF_OpenFont("assets/fonts/Roboto-Regular.ttf", 22); } void DateFormatPage::destroyFonts() { if (fontTitle_) { TTF_CloseFont(fontTitle_); fontTitle_ = nullptr; } if (fontHeader_) { TTF_CloseFont(fontHeader_); fontHeader_ = nullptr; } if (fontBody_) { TTF_CloseFont(fontBody_); fontBody_ = nullptr; } if (fontSmall_) { TTF_CloseFont(fontSmall_); fontSmall_ = nullptr; } } void DateFormatPage::destroyTextures() { titleText_.destroy(); currentText_.destroy(); statusText_.destroy(); hintText_.destroy(); for (auto& t : nameRows_) t.destroy(); nameRows_.clear(); for (auto& t : sampleRows_) t.destroy(); sampleRows_.clear(); } void DateFormatPage::handleEvent(const SDL_Event& event) { if (!state_) return; if (event.type == SDL_EVENT_KEY_DOWN) { SDL_Keycode key = event.key.key; const auto options = radiantwave::datetime::getDateFormatOptions(); if (key == SDLK_RETURN || key == SDLK_KP_ENTER) { if (selectedIndex_ >= 0 && selectedIndex_ < static_cast(options.size())) { std::string pattern = options[selectedIndex_].pattern; if (state_->db.setKV(DB_KEY, pattern)) { currentFormat_ = pattern; statusMessage_ = "Date format saved"; state_->pages.pop(*state_); } else { statusMessage_ = "Failed to save date format"; } } } else if (key == SDLK_ESCAPE) { state_->pages.pop(*state_); } } } void DateFormatPage::update(float dt) { } void DateFormatPage::render(SDL_Renderer* renderer) { int winW, winH; radiantwave::getLayoutSize(renderer, &winW, &winH); float fw = static_cast(winW); float fh = static_cast(winH); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(renderer, 20, 20, 30, 255); SDL_FRect bgRect{0, 0, fw, fh}; SDL_RenderFillRect(renderer, &bgRect); if (!fontTitle_ || !fontHeader_ || !fontBody_ || !fontSmall_) return; SDL_Color white = {255, 255, 255, 255}; SDL_Color yellow = {255, 255, 0, 255}; SDL_Color cyan = {100, 220, 255, 255}; SDL_Color gray = {180, 180, 180, 255}; const float sharedX = 100.0f; float currentY = 30.0f; titleText_.ensure(renderer, fontTitle_, "Date Format", white); if (titleText_.texture) { float x = (fw - titleText_.width) / 2.0f; SDL_FRect dst{x, currentY, titleText_.width, titleText_.height}; SDL_RenderTexture(renderer, titleText_.texture, nullptr, &dst); currentY += titleText_.height + 30.0f; } { std::string saved = radiantwave::datetime::formatDate(std::time(nullptr), currentFormat_); currentText_.ensure(renderer, fontHeader_, "Today looks like: " + saved, yellow); if (currentText_.texture) { SDL_FRect dst{sharedX, currentY, currentText_.width, currentText_.height}; SDL_RenderTexture(renderer, currentText_.texture, nullptr, &dst); } currentY += 50.0f; } const auto options = radiantwave::datetime::getDateFormatOptions(); const float margin = 12.0f; const float rowPitch = 50.0f; const time_t now = std::time(nullptr); if (nameRows_.size() != options.size()) nameRows_.resize(options.size()); if (sampleRows_.size() != options.size()) sampleRows_.resize(options.size()); for (int i = 0; i < static_cast(options.size()); ++i) { std::string label = options[i].name; std::string example = radiantwave::datetime::formatDate(now, options[i].pattern); SDL_Color color = (options[i].pattern == currentFormat_) ? yellow : white; nameRows_[i].ensure(renderer, fontBody_, label, color); if (nameRows_[i].texture) { SDL_FRect dst{sharedX, currentY, nameRows_[i].width, nameRows_[i].height}; SDL_RenderTexture(renderer, nameRows_[i].texture, nullptr, &dst); } sampleRows_[i].ensure(renderer, fontSmall_, example, gray); if (sampleRows_[i].texture) { SDL_FRect dst{sharedX + 340.0f, currentY + 8.0f, sampleRows_[i].width, sampleRows_[i].height}; SDL_RenderTexture(renderer, sampleRows_[i].texture, nullptr, &dst); } if (i == selectedIndex_) { SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_FRect line{sharedX, currentY + nameRows_[i].height + 2.0f, nameRows_[i].width, 6.0f}; SDL_RenderFillRect(renderer, &line); } currentY += rowPitch; } currentY += 20.0f; if (!statusMessage_.empty()) { statusText_.ensure(renderer, fontHeader_, statusMessage_, cyan); if (statusText_.texture) { SDL_FRect dst{sharedX, currentY, statusText_.width, statusText_.height}; SDL_RenderTexture(renderer, statusText_.texture, nullptr, &dst); } } hintText_.ensure(renderer, fontSmall_, "[UP/DOWN] Choose [ENTER] Apply & Back [ESC] Back", gray); if (hintText_.texture) { float x = (fw - hintText_.width) / 2.0f; SDL_FRect dst{x, fh - 40.0f, hintText_.width, hintText_.height}; SDL_RenderTexture(renderer, hintText_.texture, nullptr, &dst); } }