aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-08-03 15:06:57 +0200
committerdec05eba <dec05eba@protonmail.com>2021-08-05 05:50:23 +0200
commit6c85194c3b1baef0eaa011c4f1b8e48e11860f45 (patch)
tree61f3eb4304091fd2203519702a4f4daf184c5a59 /include
parentcbc6997c0a5659239d2cd971f2fa77eeda53550b (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')
-rw-r--r--include/Body.hpp205
-rw-r--r--include/BodyItem.hpp175
-rw-r--r--include/QuickMedia.hpp2
3 files changed, 212 insertions, 170 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;
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
diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp
index 0cd65b4..4399c3d 100644
--- a/include/QuickMedia.hpp
+++ b/include/QuickMedia.hpp
@@ -115,7 +115,7 @@ namespace QuickMedia {
bool page_loop(std::vector<Tab> &tabs, int start_tab_index = 0, PageLoopSubmitHandler after_submit_handler = nullptr);
void video_page_download_video(const std::string &url, sf::WindowHandle video_player_window = None);
bool video_download_if_non_streamable(std::string &video_url, std::string &audio_url, bool &is_audio_only, bool &has_embedded_audio, PageType previous_page);
- void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, BodyItems &next_play_items, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = "");
+ void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = "");
// Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
int image_page(MangaImagesPage *images_page, Body *chapters_body);
void image_continuous_page(MangaImagesPage *images_page);