#pragma once #include "Text.hpp" #include #include #include #include #include #include namespace QuickMedia { class Program; class BodyItem { public: BodyItem(std::string _title); BodyItem(const BodyItem &other); void set_title(std::string new_title) { title = std::move(new_title); dirty = true; } void append_title(std::string str) { title += str; dirty = true; } void set_description(std::string new_description) { description = std::move(new_description); dirty_description = true; } void append_description(std::string str) { description += str; dirty_description = true; } const std::string& get_title() const { return title; } const std::string& get_description() const { return description; } // TODO: Use a list of strings instead, not all plugins need all of these fields std::string url; std::string thumbnail_url; std::string attached_content_url; // TODO: Remove and use |url| instead std::string author; bool visible; bool dirty; bool dirty_description; bool thumbnail_is_local; std::unique_ptr title_text; std::unique_ptr description_text; // Used by image boards for example. The elements are indices to other body items std::vector replies; std::string post_number; sf::Color background_color; private: std::string title; std::string description; }; using BodyItems = std::vector>; class Body { public: Body(Program *program, sf::Font *font, sf::Font *bold_font); // Select previous item, ignoring invisible items. Returns true if the item was changed. This can be used to check if the top was hit when wrap_around is set to false bool select_previous_item(); // Select next item, ignoring invisible items. Returns true if the item was changed. This can be used to check if the bottom was hit when wrap_around is set to false bool select_next_item(); void set_selected_item(int item); void select_first_item(); void reset_selected(); void clear_items(); void append_items(BodyItems new_items); void clear_thumbnails(); BodyItem* get_selected() const; void clamp_selection(); void draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size); void draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress); static bool string_find_case_insensitive(const std::string &str, const std::string &substr); // TODO: Make this actually fuzzy... Right now it's just a case insensitive string find. // This would require reordering the body. // TODO: Highlight the part of the text that matches the search. // TODO: Ignore dot, whitespace and special characters void filter_search_fuzzy(const std::string &text); bool no_items_visible() const; int get_selected_item() const { return selected_item; } sf::Font *font; sf::Font *bold_font; sf::Text progress_text; sf::Text author_text; sf::Text replies_text; BodyItems items; std::thread thumbnail_load_thread; bool draw_thumbnails; bool wrap_around; // Set to {0, 0} to disable resizing sf::Vector2i thumbnail_resize_target_size; sf::Vector2f thumbnail_fallback_size; private: struct ThumbnailData { bool referenced; std::shared_ptr texture; bool loaded = false; }; Program *program; std::shared_ptr load_thumbnail_from_url(const std::string &url, bool local, sf::Vector2i thumbnail_resize_target_size); std::unordered_map item_thumbnail_textures; bool loading_thumbnail; int selected_item; }; }