aboutsummaryrefslogtreecommitdiff
path: root/include/BodyItem.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/BodyItem.hpp')
-rw-r--r--include/BodyItem.hpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/include/BodyItem.hpp b/include/BodyItem.hpp
new file mode 100644
index 0000000..ed53908
--- /dev/null
+++ b/include/BodyItem.hpp
@@ -0,0 +1,175 @@
+#pragma once
+
+#include "Text.hpp"
+#include <memory>
+#include <SFML/Graphics/Text.hpp>
+
+namespace sf {
+ class RenderTarget;
+}
+
+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
+ };
+
+ // TODO: Remove and create an Userdata class instead to replace the void* userdata in BodyItem
+ class BodyItemExtra {
+ public:
+ virtual ~BodyItemExtra() = default;
+ };
+
+ struct Reaction {
+ std::unique_ptr<Text> text;
+ void *userdata = nullptr;
+ };
+
+ class BodyItem {
+ public:
+ BodyItem(std::string _title);
+ BodyItem(const BodyItem&) = delete;
+ BodyItem& operator=(const BodyItem &other);
+
+ static std::shared_ptr<BodyItem> create(std::string title) { return std::make_shared<BodyItem>(std::move(title)); }
+
+ 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(time_t new_timestamp) {
+ if(new_timestamp == timestamp)
+ return;
+ timestamp = new_timestamp;
+ dirty_timestamp = true;
+ }
+
+ void set_title_color(sf::Color new_color) {
+ if(new_color == title_color)
+ return;
+ title_color = new_color;
+ dirty = true;
+ }
+
+ void set_description_color(sf::Color new_color) {
+ if(new_color == description_color)
+ return;
+ description_color = new_color;
+ dirty_description = true;
+ }
+
+ void set_author_color(sf::Color new_color) {
+ if(new_color == author_color)
+ return;
+ author_color = new_color;
+ dirty_author = true;
+ }
+
+ 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
+ time_t get_timestamp() const { return timestamp; }
+
+ sf::Color get_title_color() const { return title_color; }
+ sf::Color get_description_color() const { return description_color; }
+ sf::Color get_author_color() const { return author_color; }
+
+ void draw_list(Body *body, sf::RenderTarget &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;
+ bool dirty;
+ bool dirty_description;
+ bool dirty_author;
+ bool dirty_timestamp;
+ // TODO: Remove this and instead if |thumbnail_url| starts with file://, then its a local file
+ bool thumbnail_is_local;
+ std::unique_ptr<Text> title_text;
+ std::unique_ptr<Text> description_text;
+ std::unique_ptr<Text> author_text;
+ std::unique_ptr<sf::Text> timestamp_text; // TODO: Remove
+ // Used by image boards for example. The elements are indices to other body items
+ std::vector<size_t> replies_to;
+ // Used by image boards for example. The elements are indices to other body items
+ std::vector<size_t> replies;
+ std::string post_number;
+ void *userdata; // Not managed, should be deallocated by whoever sets this
+ float loaded_height = 0.0f;
+ sf::Vector2f 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<BodyItem> 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;
+ sf::Vector2i thumbnail_size;
+ std::vector<Reaction> reactions; // TODO: Move to a different body item type
+ std::shared_ptr<BodyItemExtra> extra; // TODO: Remove
+
+ // Internal use only
+ int keep_alive_frames = 0;
+ 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;
+ time_t timestamp;
+ sf::Color title_color;
+ sf::Color author_color;
+ sf::Color description_color;
+ };
+
+ using BodyItems = std::vector<std::shared_ptr<BodyItem>>;
+} \ No newline at end of file