1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
#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(int64_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
int64_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; // 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;
// 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;
float height = 0.0f;
float prev_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;
int64_t timestamp;
sf::Color title_color;
sf::Color author_color;
sf::Color description_color;
};
using BodyItems = std::vector<std::shared_ptr<BodyItem>>;
}
|