From 9bf163d51a252fb5a611e88c2e0b4123a98169e1 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 17 Oct 2020 09:40:10 +0200 Subject: Matrix: show reply messages embedded in messages that reply to them, like element does --- src/Body.cpp | 143 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 62 deletions(-) (limited to 'src/Body.cpp') diff --git a/src/Body.cpp b/src/Body.cpp index 9b12f43..f6800b8 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -6,13 +6,14 @@ #include #include -const sf::Color front_color(32, 36, 42); -const sf::Color back_color(33, 35, 37); -float image_max_height = 100.0f; -const float spacing_y = 15.0f; -const float padding_x = 10.0f; -const float image_padding_x = 5.0f; -const float padding_y = 5.0f; +static const sf::Color front_color(32, 36, 42); +static const sf::Color back_color(33, 35, 37); +static float image_max_height = 100.0f; +static const float spacing_y = 15.0f; +static const float padding_x = 10.0f; +static const float image_padding_x = 5.0f; +static const float padding_y = 5.0f; +static const float embedded_item_padding_y = 0.0f; namespace QuickMedia { BodyItem::BodyItem(std::string _title) : @@ -32,50 +33,13 @@ namespace QuickMedia { set_title(std::move(_title)); } - BodyItem::BodyItem(const BodyItem &other) { - title = other.title; - description = other.description; - url = other.url; - thumbnail_url = other.thumbnail_url; - attached_content_url = other.attached_content_url; - author = other.author; - visible = other.visible; - dirty = other.dirty; - dirty_description = other.dirty_description; - dirty_author = other.dirty_author; - dirty_timestamp = other.dirty_timestamp; - thumbnail_is_local = other.thumbnail_is_local; - if(other.title_text) - title_text = std::make_unique(*other.title_text); - else - title_text = nullptr; - if(other.description_text) - description_text = std::make_unique(*other.description_text); - else - description_text = nullptr; - if(other.author_text) - author_text = std::make_unique(*other.author_text); - else - author_text = nullptr; - if(other.timestamp_text) - timestamp_text = std::make_unique(*other.timestamp_text); - else - timestamp_text = nullptr; - replies = other.replies; - post_number = other.post_number; - title_color = other.title_color; - author_color = other.author_color; - userdata = other.userdata; - last_drawn_time = other.last_drawn_time; - timestamp = other.timestamp; - } - Body::Body(Program *program, sf::Font *font, sf::Font *bold_font, sf::Font *cjk_font) : font(font), bold_font(bold_font), cjk_font(cjk_font), progress_text("", *font, 14), replies_text("", *font, 14), + embedded_item_load_text("", *font, 14), draw_thumbnails(false), wrap_around(false), line_seperator_color(sf::Color(32, 37, 43, 255)), @@ -305,7 +269,7 @@ namespace QuickMedia { } void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size) { - draw(window, pos, size, Json::nullValue); + draw(window, pos, size, Json::Value::nullSingleton()); } // TODO: Use a render target for the whole body so all images can be put into one. @@ -395,6 +359,7 @@ namespace QuickMedia { continue; update_dirty_state(item.get(), size); + item->last_drawn_time = elapsed_time; float item_height = get_item_height(item.get()); prev_pos.y -= (item_height + spacing_y); @@ -402,7 +367,6 @@ namespace QuickMedia { if(prev_pos.y + item_height + spacing_y < start_y) break; - item->last_drawn_time = elapsed_time; // This is needed here rather than above the loop, since update_dirty_text cant be called inside scissor because it corrupts the text for some reason glEnable(GL_SCISSOR_TEST); glScissor(scissor_pos.x, (int)window_size.y - (int)scissor_pos.y - (int)scissor_size.y, scissor_size.x, scissor_size.y); @@ -420,6 +384,7 @@ namespace QuickMedia { continue; update_dirty_state(item.get(), size); + item->last_drawn_time = elapsed_time; float item_height = get_item_height(item.get()); @@ -431,7 +396,6 @@ namespace QuickMedia { if(after_pos.y - start_y >= size.y) break; - item->last_drawn_time = elapsed_time; // This is needed here rather than above the loop, since update_dirty_text cant be called inside scissor because it corrupts the text for some reason glEnable(GL_SCISSOR_TEST); glScissor(scissor_pos.x, (int)window_size.y - (int)scissor_pos.y - (int)scissor_size.y, scissor_size.x, scissor_size.y); @@ -543,17 +507,32 @@ namespace QuickMedia { } } - void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size) { + void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size, bool include_embedded_item) { update_dirty_state(item, size); item->last_drawn_time = draw_timer.getElapsedTime().asMilliseconds(); sf::Vector2u window_size = window.getSize(); glEnable(GL_SCISSOR_TEST); glScissor(pos.x, (int)window_size.y - (int)pos.y - (int)size.y, size.x, size.y); - draw_item(window, item, pos, size, get_item_height(item) + spacing_y, -1, Json::nullValue); + draw_item(window, item, pos, size, size.y + spacing_y, -1, Json::Value::nullSingleton(), include_embedded_item); glDisable(GL_SCISSOR_TEST); } - void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress) { + // TODO: Better message? maybe fallback to the reply message, or message status (such as message redacted) + static const char* embedded_item_status_to_string(EmbeddedItemStatus embedded_item_status) { + switch(embedded_item_status) { + case EmbeddedItemStatus::NONE: + return ""; + case EmbeddedItemStatus::LOADING: + return "Loading message..."; + case EmbeddedItemStatus::FINISHED_LOADING: + return "Finished loading message..."; + case EmbeddedItemStatus::FAILED_TO_LOAD: + return "Failed to load message!"; + } + return ""; + } + + void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress, bool include_embedded_item) { // TODO: Instead of generating a new hash everytime to access textures, cache the hash of the thumbnail url std::shared_ptr item_thumbnail; if(draw_thumbnails) { @@ -567,6 +546,9 @@ namespace QuickMedia { item_thumbnail->referenced = true; } + if(body_item_render_callback) + body_item_render_callback(item); + sf::Vector2f item_pos; item_pos.x = std::floor(pos.x); item_pos.y = std::floor(pos.y); @@ -605,9 +587,10 @@ namespace QuickMedia { } } + const float timestamp_text_y = std::floor(item_pos.y + padding_y - 6.0f); if(item->author_text) { item->author_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 6.0f)); - item->author_text->setMaxWidth(size.x - text_offset_x - image_padding_x * 2.0f); + item->author_text->setMaxWidth(size.x - text_offset_x - image_padding_x); item->author_text->draw(window); sf::Vector2f replies_text_pos = item->author_text->getPosition() + sf::Vector2f(0.0f, 5.0f); @@ -625,28 +608,48 @@ namespace QuickMedia { item_pos.y += item->author_text->getHeight() - 2.0f; } + + if(include_embedded_item && item->embedded_item_status != EmbeddedItemStatus::NONE) { + float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), true, false) : (embedded_item_load_text.getLocalBounds().height + embedded_item_padding_y * 2.0f); + const float border_width = 4.0f; + sf::RectangleShape border_left(sf::Vector2f(border_width, std::floor(embedded_item_height))); + border_left.setFillColor(sf::Color::White); + border_left.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + 4.0f)); + window.draw(border_left); + + if(item->embedded_item) { + sf::Vector2f embedded_item_pos(std::floor(item_pos.x + text_offset_x + border_width + padding_x), std::floor(item_pos.y + embedded_item_padding_y + 4.0f)); + sf::Vector2f embedded_item_size(std::floor(size.x - text_offset_x - border_width - padding_x), embedded_item_height); + draw_item(window, item->embedded_item.get(), embedded_item_pos, embedded_item_size, false); + } else { + embedded_item_load_text.setString(embedded_item_status_to_string(item->embedded_item_status)); + embedded_item_load_text.setPosition(std::floor(item_pos.x + text_offset_x + border_width + padding_x), std::floor(item_pos.y + embedded_item_height * 0.5f - embedded_item_load_text.getLocalBounds().height * 0.5f + 4.0f)); + window.draw(embedded_item_load_text); + } + item_pos.y += embedded_item_height + 4.0f; + } + //title_text.setString(item->title); //title_text.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y)); //window.draw(title_text); if(item->title_text) { item->title_text->setFillColor(item->title_color); - item->title_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 8.0f)); - item->title_text->setMaxWidth(size.x - text_offset_x - image_padding_x * 2.0f); + item->title_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 6.0f)); + item->title_text->setMaxWidth(size.x - text_offset_x - image_padding_x); item->title_text->draw(window); + item_pos.y += item->title_text->getHeight() - 2.0f; } if(item->description_text) { float height_offset = 0.0f; - if(!item->get_title().empty()) { - height_offset = item->title_text->getHeight(); - } - item->description_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 8.0f + height_offset)); - item->description_text->setMaxWidth(size.x - text_offset_x - image_padding_x * 2.0f); + item->description_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 6.0f + height_offset)); + item->description_text->setMaxWidth(size.x - text_offset_x - image_padding_x); item->description_text->draw(window); + item_pos.y += item->description_text->getHeight() - 2.0f; } if(item->timestamp_text) { - item->timestamp_text->setPosition(std::floor(item_pos.x + size.x - item->timestamp_text->getLocalBounds().width - padding_x), std::floor(item_pos.y + padding_y - 18.0f)); + item->timestamp_text->setPosition(std::floor(item_pos.x + size.x - item->timestamp_text->getLocalBounds().width - padding_x), timestamp_text_y + 4.0f); window.draw(*item->timestamp_text); } @@ -662,13 +665,13 @@ namespace QuickMedia { if(current_json.isNumeric() && total_json.isNumeric()) { progress_text.setString(std::string("Page: ") + std::to_string(current_json.asInt()) + "/" + std::to_string(total_json.asInt())); auto bounds = progress_text.getLocalBounds(); - progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - padding_x), std::floor(item_pos.y + padding_y)); + progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - padding_x), timestamp_text_y + 6.0f); window.draw(progress_text); } } } - float Body::get_item_height(BodyItem *item, bool load_texture) { + float Body::get_item_height(BodyItem *item, bool load_texture, bool include_embedded_item) { float item_height = 0.0f; if(item->title_text) { item_height += item->title_text->getHeight() - 2.0f; @@ -676,6 +679,12 @@ namespace QuickMedia { if(item->author_text) { item_height += item->author_text->getHeight() - 2.0f; } + if(include_embedded_item && item->embedded_item_status != EmbeddedItemStatus::NONE) { + if(item->embedded_item) + item_height += (get_item_height(item->embedded_item.get(), load_texture, false) + 4.0f + embedded_item_padding_y * 2.0f); + else + item_height += (embedded_item_load_text.getLocalBounds().height + 4.0f + embedded_item_padding_y * 2.0f); + } if(item->description_text) { item_height += item->description_text->getHeight() - 2.0f; } @@ -757,4 +766,14 @@ namespace QuickMedia { } return true; } + + bool Body::is_selected_item_last_visible_item() const { + if(selected_item < 0 || selected_item >= (int)items.size() || !items[selected_item]->visible) + return false; + for(int i = selected_item + 1; i < (int)items.size(); ++i) { + if(items[i]->visible) + return false; + } + return true; + } } \ No newline at end of file -- cgit v1.2.3