#pragma once #include "Text.hpp" #include #include #include namespace mgl { class Window; } namespace QuickMedia { class Body; enum class FetchStatus { NONE, QUEUED_LOADING, LOADING, FINISHED_LOADING, FAILED_TO_LOAD }; enum class ThumbnailMaskType { NONE, CIRCLE, ROUNDED_RECTANGLE }; enum BodyTheme : int { BODY_THEME_MINIMAL, BODY_THEME_MODERN_SPACIOUS }; struct ThumbnailWidget { mgl::vec2f position; mgl::vec2f size; }; struct Widgets { std::optional thumbnail; }; // TODO: Remove and create an Userdata class instead to replace the void* userdata in BodyItem class BodyItemExtra { public: virtual ~BodyItemExtra() = default; virtual void draw_overlay(mgl::Window &window, const Widgets &widgets) { (void)window; (void)widgets; } }; struct Reaction { std::string text_str; std::unique_ptr text; void *userdata = nullptr; mgl::vec2f size; mgl::Color text_color; }; class BodyItem { public: BodyItem(const BodyItem&) = delete; BodyItem& operator=(const BodyItem &other); static std::shared_ptr create(std::string title, bool selectable = true); void set_title(std::string new_title) { if(title == new_title) return; title = std::move(new_title); dirty = true; } void set_description(std::string new_description) { if(description == new_description) return; description = std::move(new_description); dirty_description = true; } void set_author(std::string new_author) { if(author == new_author) return; author = std::move(new_author); dirty_author = true; } // |new_timestamp| is in milliseconds void set_timestamp(int64_t new_timestamp) { if(new_timestamp == timestamp) return; timestamp = new_timestamp; dirty_timestamp = true; } void set_title_color(mgl::Color new_color) { if(new_color == title_color) return; title_color = new_color; dirty = true; } void set_description_color(mgl::Color new_color) { if(new_color == description_color) return; description_color = new_color; dirty_description = true; } void set_author_color(mgl::Color new_color) { if(new_color == author_color) return; author_color = new_color; dirty_author = true; } void add_reaction(std::string text, void *userdata, mgl::Color text_color); void add_reaction(std::string text, void *userdata); // Returns true if reaction is found bool remove_reaction_by_userdata(void *userdata) { for(auto it = reactions.begin(); it != reactions.end(); ++it) { if(it->userdata == userdata) { reactions.erase(it); return true; } } return false; } const std::string& get_title() const { return title; } const std::string& get_description() const { return description; } const std::string& get_author() const { return author; } // In milliseconds int64_t get_timestamp() const { return timestamp; } mgl::Color get_title_color() const { return title_color; } mgl::Color get_description_color() const { return description_color; } mgl::Color get_author_color() const { return author_color; } bool is_selectable() const { return selectable; } void draw_list(Body *body, mgl::Window &render_target); // TODO: Use a list of strings instead, not all plugins need all of these fields std::string url; std::string thumbnail_url; bool visible; // TODO: Make private and when set by user, set a |visible_force| variable to true or false which makes the item invisible even after filtering bool dirty; bool dirty_description; bool dirty_author; bool dirty_timestamp; bool dirty_reactions; // TODO: Remove this and instead if |thumbnail_url| starts with file://, then its a local file bool thumbnail_is_local; std::unique_ptr title_text; std::unique_ptr description_text; std::unique_ptr author_text; std::unique_ptr timestamp_text; // TODO: Remove // Used by image boards for example. The elements are indices to other body items std::vector replies_to; // Used by image boards for example. The elements are indices to other body items std::vector replies; std::string post_number; void *userdata; // Not managed, should be deallocated by whoever sets this float loaded_height = 0.0f; float height = 0.0f; float prev_height = 0.0f; mgl::vec2f loaded_image_size; float loaded_content_height = 0.0f; FetchStatus embedded_item_status = FetchStatus::NONE; // Important! Should refer to a new BodyItem, not one that already exists in the body. // TODO: Allow referring to an existing body item. This doesn't work properly at the moment because max width of text and line count calculation getting messed up // if an embedded item wraps but not the original body item. std::shared_ptr embedded_item; // Used by matrix for example to display reply message body. Note: only the first level of embedded items is rendered (not recursive, this is done on purpose) ThumbnailMaskType thumbnail_mask_type = ThumbnailMaskType::NONE; mgl::vec2i thumbnail_size; std::vector reactions; // TODO: Move to a different body item type std::shared_ptr extra; // TODO: Remove // Internal use only int keep_alive_frames = 0; private: BodyItem(std::string _title, bool selectable); private: // TODO: Clean up these strings when set in text, and get_title for example should return |title_text.getString()| // TODO: Use sf::String instead, removes the need to convert to utf32 every time the text is dirty (for example when resizing window) std::string title; std::string description; std::string author; int64_t timestamp; mgl::Color title_color; mgl::Color author_color; mgl::Color description_color; bool selectable; }; using BodyItems = std::vector>; }