BodyItem.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #pragma once
  2. #include "Text.hpp"
  3. #include <memory>
  4. #include <optional>
  5. #include <mglpp/graphics/Text.hpp>
  6. namespace mgl {
  7. class Window;
  8. }
  9. namespace QuickMedia {
  10. class Body;
  11. enum class FetchStatus {
  12. NONE,
  13. QUEUED_LOADING,
  14. LOADING,
  15. FINISHED_LOADING,
  16. FAILED_TO_LOAD
  17. };
  18. enum class ThumbnailMaskType {
  19. NONE,
  20. CIRCLE,
  21. ROUNDED_RECTANGLE
  22. };
  23. enum BodyTheme : int {
  24. BODY_THEME_MINIMAL,
  25. BODY_THEME_MODERN_SPACIOUS
  26. };
  27. struct ThumbnailWidget {
  28. mgl::vec2f position;
  29. mgl::vec2f size;
  30. };
  31. class BodyItem;
  32. struct Widgets {
  33. BodyItem *body_item = nullptr;
  34. std::optional<ThumbnailWidget> thumbnail;
  35. };
  36. // TODO: Remove and create an Userdata class instead to replace the void* userdata in BodyItem
  37. class BodyItemExtra {
  38. public:
  39. BodyItemExtra() = default;
  40. virtual ~BodyItemExtra() = default;
  41. virtual void draw_overlay(mgl::Window &window, const Widgets &widgets) {
  42. (void)window;
  43. (void)widgets;
  44. }
  45. };
  46. struct Reaction {
  47. std::string text_str;
  48. std::unique_ptr<Text> text;
  49. void *userdata = nullptr;
  50. mgl::vec2f size;
  51. mgl::Color text_color;
  52. int num_lines = 1;
  53. };
  54. class BodyItem {
  55. public:
  56. BodyItem(const BodyItem&) = delete;
  57. BodyItem& operator=(const BodyItem &other);
  58. static std::shared_ptr<BodyItem> create(std::string title, bool selectable = true);
  59. void set_title(std::string new_title) {
  60. if(title == new_title)
  61. return;
  62. title = std::move(new_title);
  63. dirty = true;
  64. }
  65. void set_description(std::string new_description) {
  66. if(description == new_description)
  67. return;
  68. description = std::move(new_description);
  69. dirty_description = true;
  70. }
  71. void set_author(std::string new_author) {
  72. if(author == new_author)
  73. return;
  74. author = std::move(new_author);
  75. dirty_author = true;
  76. }
  77. // |new_timestamp| is in milliseconds
  78. void set_timestamp(int64_t new_timestamp) {
  79. if(new_timestamp == timestamp)
  80. return;
  81. timestamp = new_timestamp;
  82. dirty_timestamp = true;
  83. }
  84. void set_title_color(mgl::Color new_color, bool new_force_color = false) {
  85. if(new_color == title_color && new_force_color == force_description_color)
  86. return;
  87. title_color = new_color;
  88. dirty = true;
  89. force_title_color = new_force_color;
  90. }
  91. // Set to 0 to disable max lines
  92. void set_title_max_lines(int max_lines) {
  93. if(max_lines == title_max_lines)
  94. return;
  95. title_max_lines = max_lines;
  96. dirty = true;
  97. }
  98. void set_description_color(mgl::Color new_color, bool new_force_color = false) {
  99. if(new_color == description_color && new_force_color == force_description_color)
  100. return;
  101. description_color = new_color;
  102. dirty_description = true;
  103. force_description_color = new_force_color;
  104. }
  105. void set_description_max_lines(int max_lines) {
  106. if(max_lines == description_max_lines)
  107. return;
  108. description_max_lines = max_lines;
  109. dirty_description = true;
  110. }
  111. void set_author_color(mgl::Color new_color, bool new_force_color = false) {
  112. if(new_color == author_color && new_force_color == force_description_color)
  113. return;
  114. author_color = new_color;
  115. dirty_author = true;
  116. force_author_color = new_force_color;
  117. }
  118. void add_reaction(std::string text, void *userdata, mgl::Color text_color);
  119. void add_reaction(std::string text, void *userdata);
  120. // Returns true if reaction is found
  121. bool remove_reaction_by_userdata(void *userdata) {
  122. for(auto it = reactions.begin(); it != reactions.end(); ++it) {
  123. if(it->userdata == userdata) {
  124. reactions.erase(it);
  125. return true;
  126. }
  127. }
  128. return false;
  129. }
  130. const std::string& get_title() const { return title; }
  131. const std::string& get_description() const { return description; }
  132. const std::string& get_author() const { return author; }
  133. // In milliseconds
  134. int64_t get_timestamp() const { return timestamp; }
  135. mgl::Color get_title_color() const { return title_color; }
  136. mgl::Color get_description_color() const { return description_color; }
  137. mgl::Color get_author_color() const { return author_color; }
  138. bool is_selectable() const { return selectable; }
  139. void draw_list(Body *body, mgl::Window &render_target);
  140. // TODO: Bits for bools
  141. // TODO: Use a list of strings instead, not all plugins need all of these fields
  142. std::string url;
  143. std::string thumbnail_url;
  144. int title_max_lines = 0;
  145. int description_max_lines = 0;
  146. 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
  147. bool dirty;
  148. bool dirty_description;
  149. bool dirty_author;
  150. bool dirty_timestamp;
  151. bool dirty_reactions;
  152. // TODO: Remove this and instead if |thumbnail_url| starts with file://, then its a local file
  153. bool thumbnail_is_local;
  154. bool force_title_color = false;
  155. bool force_description_color = false;
  156. bool force_author_color = false;
  157. std::unique_ptr<Text> title_text;
  158. std::unique_ptr<Text> description_text;
  159. std::unique_ptr<Text> author_text;
  160. std::unique_ptr<mgl::Text> timestamp_text; // TODO: Remove
  161. void *userdata; // Not managed, should be deallocated by whoever sets this
  162. float loaded_height = 0.0f;
  163. float height = 0.0f;
  164. float prev_height = 0.0f;
  165. mgl::vec2f loaded_image_size;
  166. float loaded_content_height = 0.0f;
  167. FetchStatus embedded_item_status = FetchStatus::NONE;
  168. // Important! Should refer to a new BodyItem, not one that already exists in the body.
  169. // 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
  170. // if an embedded item wraps but not the original body item.
  171. 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)
  172. ThumbnailMaskType thumbnail_mask_type = ThumbnailMaskType::NONE;
  173. mgl::vec2i thumbnail_size;
  174. std::vector<Reaction> reactions; // TODO: Move to a different body item type
  175. std::shared_ptr<BodyItemExtra> extra; // TODO: Remove
  176. // Internal use only
  177. int keep_alive_frames = 0;
  178. private:
  179. BodyItem(std::string _title, bool selectable);
  180. private:
  181. // TODO: Clean up these strings when set in text, and get_title for example should return |title_text.getString()|
  182. // TODO: Use sf::String instead, removes the need to convert to utf32 every time the text is dirty (for example when resizing window)
  183. std::string title;
  184. std::string description;
  185. std::string author;
  186. int64_t timestamp;
  187. mgl::Color title_color;
  188. mgl::Color author_color;
  189. mgl::Color description_color;
  190. bool selectable;
  191. };
  192. using BodyItems = std::vector<std::shared_ptr<BodyItem>>;
  193. }