Files
radiantwave/src/proclamation_options_page.h
T

95 lines
3.5 KiB
C++

#pragma once
#include "page.h"
#include "db/database_manager.h"
#include "text_cache.h"
#include <SDL3_ttf/SDL_ttf.h>
#include <cstdint>
#include <string>
#include <vector>
// The always-on top-level proclamation. It can neither be selected nor
// deselected, is never shown inside a category, and is always flagged as
// selected in the database. Set this to the correct proclamation ID.
constexpr const char* DEFAULT_PROPLEAMATION_ID = "f3d42354-3197-45e4-9b08-be447f14386d";
// Display name used for the always-on top-level proclamation.
constexpr const char* DEFAULT_PROPLEAMATION_NAME = "Synchronize, Harmonize & Energize";
class ProclamationOptionsPage : public Page {
public:
void onPush(AppState& state) override;
void onResume(AppState& state) override;
void onPause(AppState& state) override;
void onPop(AppState& state) override;
void handleEvent(const SDL_Event& event) override;
void update(float dt) override;
void render(SDL_Renderer* renderer) override;
private:
struct FlatItem {
enum class Type { ScheduleToggle, Category, Group, Proclamation };
Type type = Type::Proclamation;
std::string id; // category id, group id, proclamation id, or "schedule"
std::string label; // display text
int depth = 0; // 0 = category / default, 1 = group, 2 = proclamation
bool expanded = false; // categories and groups only
bool selected = false; // proclamations and the schedule toggle
bool isDefault = false; // the always-on top-level proclamation
};
void loadFromDb();
void rebuildItems();
void rebuildVisible();
void toggleItem();
void toggleSearchItem();
void collapseCurrent();
void expandCurrent();
void moveToParent();
void saveSelectionToDb();
void clearAllSelections();
void ensureHighlightVisible();
void scrollTo(int target);
void createFonts();
void destroyFonts();
void destroyTextures();
// Search mode. Activates on the first typed character and filters the
// flat proclamation pool (title + content) with word-prefix matching.
void enterSearchMode();
void exitSearchMode();
void rebuildSearchResults();
void appendSearchText(const char* utf8);
bool searchActive() const { return searchActive_; }
int activeListSize() const;
AppState* state_ = nullptr;
std::vector<radiantwave::db::ProclamationRecord> proclamations_;
std::vector<radiantwave::db::ProclamationCategoryRecord> categories_;
std::vector<radiantwave::db::ProclamationGroupRecord> groups_;
std::vector<FlatItem> items_;
std::vector<size_t> visible_; // indices into items_, in display order
std::vector<size_t> searchResults_; // indices into proclamations_, search mode
std::vector<std::string> searchPool_; // lowercase title + content per proclamation
int highlightIndex_ = 0; // index into the active list
int scrollOffset_ = 0;
int visibleCount_ = 8; // rows that fit on screen (recomputed each frame)
std::string statusMessage_;
bool searchActive_ = false;
std::string searchQuery_;
TTF_Font* fontTitle_ = nullptr;
TTF_Font* fontItem_ = nullptr;
TTF_Font* fontSmall_ = nullptr;
CachedText titleText_;
CachedText statusText_;
CachedText searchText_;
CachedText emptyHintText_;
CachedText footerText_;
std::vector<CachedText> rowTexts_;
std::vector<CachedText> searchRowTexts_; // indexed by proclamations_ id
};