#pragma once #include "page.h" #include "db/database_manager.h" #include "text_cache.h" #include #include #include #include // 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 { RootCategory, SubCategory, Proclamation }; Type type = Type::Proclamation; std::string id; // category id or proclamation id std::string label; // display text int depth = 0; // 0 = root category / default, 1 = sub-category, 2 = proclamation bool expanded = false; // categories only bool selected = false; // proclamations only 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 proclamations_; std::vector categories_; std::vector items_; std::vector visible_; // indices into items_, in display order std::vector searchResults_; // indices into proclamations_, search mode std::vector 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 rowTexts_; std::vector searchRowTexts_; // indexed by proclamations_ id };