diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-08-03 15:06:57 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-08-05 05:50:23 +0200 |
commit | 6c85194c3b1baef0eaa011c4f1b8e48e11860f45 (patch) | |
tree | 61f3eb4304091fd2203519702a4f4daf184c5a59 /include/Body.hpp | |
parent | cbc6997c0a5659239d2cd971f2fa77eeda53550b (diff) |
Make body items private, add accessor functions
This allows body to automatically update dirty state (and other states).
Correctly format newlines in codeblocks in matrix.
Diffstat (limited to 'include/Body.hpp')
-rw-r--r-- | include/Body.hpp | 205 |
1 files changed, 36 insertions, 169 deletions
diff --git a/include/Body.hpp b/include/Body.hpp index 43fdf22..b44a386 100644 --- a/include/Body.hpp +++ b/include/Body.hpp @@ -1,9 +1,8 @@ #pragma once -#include "Text.hpp" +#include "BodyItem.hpp" #include "AsyncImageLoader.hpp" #include "RoundedRectangle.hpp" -#include <SFML/Graphics/Text.hpp> #include <SFML/Graphics/RectangleShape.hpp> #include <SFML/Graphics/Sprite.hpp> #include <json/value.h> @@ -18,171 +17,22 @@ namespace sf { } namespace QuickMedia { - class Program; - - 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; - }; + using BodyItemRenderCallback = std::function<void(std::shared_ptr<BodyItem> &body_item)>; + // Return true to merge + using BodyItemMergeHandler = std::function<bool(BodyItem *prev_item, BodyItem *this_item)>; - class BodyItem { + class BodyItemList { 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; } - - // 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; + BodyItemList(BodyItems *body_items) : body_items(body_items) {} + std::shared_ptr<BodyItem>* data() { return body_items->data(); } + const std::shared_ptr<BodyItem>* data() const { return body_items->data(); } + std::shared_ptr<BodyItem>& operator[](size_t index) { return (*body_items)[index]; } + const std::shared_ptr<BodyItem>& operator[](size_t index) const { return (*body_items)[index]; } + size_t size() const { return body_items->size(); } 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; + BodyItems *body_items; }; - using BodyItems = std::vector<std::shared_ptr<BodyItem>>; - using BodyItemRenderCallback = std::function<void(std::shared_ptr<BodyItem> &body_item)>; - // Return true to merge - using BodyItemMergeHandler = std::function<bool(BodyItem *prev_item, BodyItem *this_item)>; - enum class AttachSide { TOP, BOTTOM @@ -212,13 +62,34 @@ namespace QuickMedia { void select_first_item(bool reset_page_scroll = true); void select_last_item(); + void set_items(BodyItems items); void clear_items(); + void prepend_item(std::shared_ptr<BodyItem> body_item); void prepend_items_reverse(BodyItems new_items); + void append_item(std::shared_ptr<BodyItem> body_item); void append_items(BodyItems new_items); + void insert_item(std::shared_ptr<BodyItem> body_item, int index); + void move_items_to(Body *other_body); + void move_item(size_t src_index, size_t dst_index); // Returns the inserted position size_t insert_item_by_timestamp(std::shared_ptr<BodyItem> body_item); // Note: keeps the selected item (moving the selected_item index if necessary) void insert_items_by_timestamps(BodyItems new_items); + void for_each_item(std::function<void(std::shared_ptr<BodyItem>&)> callback); + // Return true if the item is the match + std::shared_ptr<BodyItem> find_item(std::function<bool(std::shared_ptr<BodyItem>&)> callback); + // Returns -1 if no item is found + int find_item_index(std::function<bool(std::shared_ptr<BodyItem>&)> callback); + // Return true to remove the current item. + // Returns true if the item was found. + bool erase_item(std::function<bool(std::shared_ptr<BodyItem>&)> callback); + std::shared_ptr<BodyItem> get_item_by_index(size_t index); + BodyItemList get_items(); + BodyItems get_items_copy(); + // If |end_index| is (size_t)-1, then all items starting from |start_index| until the end are copied + void copy_range(size_t start_index, size_t end_index, BodyItems &target); + size_t get_num_items() const; + void reverse_items(); void clear_cache(); void clear_text_cache(); @@ -255,17 +126,12 @@ namespace QuickMedia { // This is the item we can see the end of bool is_bottom_cut_off() const { return bottom_cut_off; } int get_num_visible_items() const { return num_visible_items; }; - - // Call this once after adding new items - void items_set_dirty(bool force = false); void apply_search_filter_for_item(BodyItem *body_item); bool can_move_left() const { return selected_column > 0; } bool can_move_right() const { return selected_column + 1 < num_columns; } - // TODO: Prevent items from being removed when render is in progress. That would invalidate references and cause a crash - BodyItems items; bool draw_thumbnails; // Set to {0, 0} to disable resizing sf::Vector2i thumbnail_max_size; @@ -315,6 +181,9 @@ namespace QuickMedia { BOTTOM }; + // TODO: Prevent items from being removed when render is in progress. That would invalidate references and cause a crash + BodyItems items; + BodyTheme body_theme; int selected_item; @@ -376,8 +245,6 @@ namespace QuickMedia { sf::Vector2f item_background_target_size; float item_background_target_height = 0.0f; TargetSetState target_set = TargetSetState::NOT_SET; - // TODO: Instead of using this, add functions for modifying |items| and apply the filter on those new items - DirtyState items_dirty = DirtyState::FALSE; std::string current_filter; bool using_filter = false; sf::Shader *rounded_rectangle_mask_shader; |