From 63774155016ad581dcf418c94cd2ec84fcf86445 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 18 Sep 2021 17:03:11 +0200 Subject: Render selected item background as a rectangle on top instead of banding Limit selected item background position to body content position and size --- src/Body.cpp | 306 ++++++++++++++++++++++++++++------------------- src/RoundedRectangle.cpp | 33 ++--- 2 files changed, 201 insertions(+), 138 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 1b300c5..5509938 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -609,21 +609,17 @@ namespace QuickMedia { const float scissor_y = pos.y; pos.y = 0.0f; - if(!rendering_card_view) + if(!rendering_card_view) { pos.x += body_spacing[body_theme].body_padding_horizontal; + size.x = std::max(0.0f, size.x - body_spacing[body_theme].body_padding_horizontal * 2.0f); + } if(attach_side == AttachSide::TOP) pos.y += body_spacing[body_theme].body_padding_vertical; - if(!rendering_card_view) - size.x = std::max(0.0f, size.x - body_spacing[body_theme].body_padding_horizontal * 2.0f); - float frame_time = frame_timer.restart().asSeconds(); if(frame_time > 1.0f) frame_time = 1.0f; - // TODO: Remove the need for this. This is needed because fps is changed to 20 or 2 when idle. That idle handler should be removed - //if(frame_time > 0.01666f) - // frame_time = 0.01666f; if(selected_item >= (int)items.size()) selected_item = (int)items.size() - 1; @@ -637,7 +633,6 @@ namespace QuickMedia { elapsed_time_sec = draw_timer.getElapsedTime().asSeconds(); - const int prev_num_visible_items = num_visible_items; const bool prev_items_cut_off = top_cut_off || bottom_cut_off; const int prev_first_visible_item = first_visible_item; const int prev_last_visible_item = last_visible_item; @@ -781,7 +776,7 @@ namespace QuickMedia { if(rendering_card_view) { draw_card_view(window, pos, size, window_size, scissor_y); } else { - body_total_height = draw_list_view(window, pos, size, prev_num_visible_items, content_progress); + body_total_height = draw_list_view(window, pos, size, content_progress); } window.setView(prev_view); @@ -1002,16 +997,17 @@ namespace QuickMedia { } } - float Body::draw_list_view(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const int prev_num_visible_items, const Json::Value &content_progress) { - const int num_items = items.size(); + static float clamp(float value, float min, float max) { + return std::min(max, std::max(min, value)); + } - if(prev_num_visible_items > 0 && render_selected_item_bg && body_theme == BODY_THEME_MINIMAL) { - item_background.set_position(sf::Vector2f(pos.x, item_background_prev_pos.y)); - item_background.set_size(item_background_prev_size); - item_background.set_color(get_theme().selected_color); - item_background.set_band(sf::Vector2f(0.0f, 0.0f), sf::Vector2f(0.0f, 0.0f)); - item_background.draw(window); - } + static sf::Vector2f round(sf::Vector2f vec) { + return { std::floor(vec.x), std::floor(vec.y) }; + } + + float Body::draw_list_view(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress) { + const int num_items = items.size(); + const float pos_y_before_scroll = pos.y; int index = -1; if(attach_side == AttachSide::TOP) { @@ -1083,22 +1079,29 @@ namespace QuickMedia { get_item_height(item.get(), size.x, true, true, merge_with_previous, index); if(attach_side == AttachSide::BOTTOM) pos.y -= (item->loaded_height + body_spacing[body_theme].spacing_y); - //page_scroll += add_height; - - //const float top_y_clamped = clamp(pos.y, 0.0f, size.y); - //const float bottom_y_clamped = std::min(pos.y + item->current_loaded_height, size.y); - - //float offset_y = 0.0f; - //if(pos.y < 0.0f) - // offset_y = pos.y; - //else if(pos.y > size.y) - // offset_y = size.y - pos.y; + + RenderItem render_item; + render_item.body_item = item; + render_item.pos = pos; + render_item.size = size; + render_item.item_height = item->loaded_height; + render_item.item_index = index; + render_item.merge_with_previous = merge_with_previous; + render_items.push_back(std::move(render_item)); - //sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, scissor_y + bottom_y_clamped)); - //new_view.setViewport(sf::FloatRect(0.0f, (scissor_y + top_y_clamped) / (float)window_size.y, 1.0f, (scissor_y + bottom_y_clamped) / (float)window_size.y)); - //window.setView(new_view); + { + sf::Vector2f item_pos; + item_pos.x = std::floor(pos.x); + item_pos.y = std::floor(pos.y); + + if(body_theme == BODY_THEME_MODERN_SPACIOUS) { + item_background.set_position(item_pos); + item_background.set_size(sf::Vector2f(size.x, item->loaded_height)); + item_background.set_color(get_theme().shade_color); + item_background.draw(window); + } + } - draw_item(window, item, pos/*sf::Vector2f(pos.x, offset_y)*/, size, item->loaded_height, index, content_progress, true, merge_with_previous); handle_item_render(pos, size.x, item->loaded_height, index); ++num_visible_items; @@ -1151,6 +1154,33 @@ namespace QuickMedia { } } + for(RenderItem &render_item : render_items) { + if(render_item.item_index == selected_item) { + float offset_y_spacing = -body_spacing[body_theme].spacing_y; + if(attach_side == AttachSide::BOTTOM) + offset_y_spacing = body_spacing[body_theme].spacing_y; + + if(selected_item_fits_in_body) { + item_background.set_position(round( + sf::Vector2f( + item_background_prev_pos.x, + clamp(item_background_prev_pos.y, pos_y_before_scroll, pos_y_before_scroll + size.y - item_background_prev_size.y - body_spacing[body_theme].body_padding_vertical + offset_y_spacing)))); + } else { + item_background.set_position(round(item_background_prev_pos)); + } + + item_background.set_size(item_background_prev_size); + item_background.set_color(get_theme().selected_color); + item_background.draw(window); + break; + } + } + + for(RenderItem &render_item : render_items) { + draw_item(window, render_item.body_item, render_item.pos, render_item.size, render_item.item_height, render_item.item_index, content_progress, true, render_item.merge_with_previous); + } + + render_items.clear(); return pos.y - pos_y_start; } @@ -1230,95 +1260,25 @@ namespace QuickMedia { item_height = std::min(card_height, item_height + (item_thumbnail ? card_image_text_padding : 0) + card_padding_y * 2 + 5); row_max_height = std::max(row_max_height, item_height); - handle_item_render(pos + pos_offset, card_width, item_height, item_index); + RenderItem render_item; + render_item.body_item = item; + render_item.pos = pos; + render_item.pos_offset = pos_offset; + render_item.item_height = item_height; + render_item.item_index = item_index; + render_item.item_thumbnail = item_thumbnail; + render_items.push_back(std::move(render_item)); + sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, size.y)); new_view.setViewport(sf::FloatRect(0.0f, scissor_y / (float)window_size.y, 1.0f, size.y / (float)window_size.y)); window.setView(new_view); - item_background.set_position(pos + pos_offset); - item_background.set_size(sf::Vector2f(card_width, item_height)); + item_background.set_position(round(pos + pos_offset)); + item_background.set_size(round(sf::Vector2f(card_width, item_height))); item_background.set_color(get_theme().card_item_background_color); - item_background.set_band(item_background_prev_pos - (pos + pos_offset), item_background_prev_size); - item_background.set_band_color(get_theme().selected_color); item_background.draw(window); - { - float image_height = 0.0f; - if(item_thumbnail && item_thumbnail->loading_state == LoadingState::APPLIED_TO_TEXTURE && item_thumbnail->texture.getNativeHandle() != 0) { - image.setTexture(item_thumbnail->texture, true); - auto image_size = image.getTexture()->getSize(); - sf::Vector2f image_size_f(image_size.x, image_size.y); - sf::Vector2f content_size = to_vec2f(thumbnail_size); - auto new_image_size = clamp_to_size(image_size_f, content_size); - auto image_scale = get_ratio(image_size_f, new_image_size); - image.setScale(image_scale); - image.setPosition(pos + pos_offset + sf::Vector2f(card_padding_x, card_padding_y) + sf::Vector2f(card_max_image_size.x * 0.5f, 0.0f) - sf::Vector2f(new_image_size.x * 0.5f, 0.0f)); - image_height = new_image_size.y; - if(thumbnail_mask_shader && item->thumbnail_mask_type == ThumbnailMaskType::CIRCLE) { - thumbnail_mask_shader->setUniform("resolution", new_image_size); - window.draw(image, thumbnail_mask_shader); - } else if(rounded_rectangle_mask_shader) { - rounded_rectangle_mask_shader->setUniform("radius", 10.0f); - rounded_rectangle_mask_shader->setUniform("resolution", new_image_size); - window.draw(image, rounded_rectangle_mask_shader); - } else { - window.draw(image); - } - } else if(!item->thumbnail_url.empty()) { - sf::Vector2f content_size = to_vec2f(thumbnail_size); - sf::Vector2f loading_icon_size(loading_icon.getTexture()->getSize().x, loading_icon.getTexture()->getSize().y); - auto new_loading_icon_size = clamp_to_size(loading_icon_size, content_size); - loading_icon.setPosition(pos + pos_offset + sf::Vector2f(card_padding_x, card_padding_y) + sf::Vector2f(card_max_image_size.x, content_size.y) * 0.5f); - loading_icon.setScale(get_ratio(loading_icon_size, new_loading_icon_size)); - loading_icon.setRotation(elapsed_time_sec * 400.0); - window.draw(loading_icon); - image_height = content_size.y; - } - - const float text_padding = item_thumbnail ? card_image_text_padding : 0.0f; - - sf::Vector2f text_pos = sf::Vector2f(pos.x, scissor_y + body_spacing[body_theme].body_padding_vertical) + pos_offset + sf::Vector2f(card_padding_x, card_padding_y) + sf::Vector2f(0.0f, image_height + text_padding); - const float text_height = (item_height - card_padding_y * 2.0f) - image_height - text_padding; - - const float underflow_text = text_pos.y - scissor_y; - const float underflow_height = underflow_text < 0.0f ? std::max(0.0f, text_height + underflow_text) : text_height; - sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, underflow_height)); - new_view.setViewport(sf::FloatRect(0.0f, std::max(text_pos.y, scissor_y) / (float)window_size.y, 1.0f, underflow_height / (float)window_size.y)); - window.setView(new_view); - - text_pos.y = std::min(0.0f, underflow_text); - float text_offset_y = 0.0f; - if(item->author_text) { - item->author_text->setPosition(text_pos); - item->author_text->draw(window); - text_offset_y += item->author_text->getHeight(); - } - - if(item->title_text) { - item->title_text->setPosition(text_pos + sf::Vector2f(0.0f, text_offset_y)); - item->title_text->draw(window); - text_offset_y += item->title_text->getHeight(); - } - - if(item->description_text) { - item->description_text->setPosition(text_pos + sf::Vector2f(0.0f, text_offset_y)); - item->description_text->draw(window); - text_offset_y += item->description_text->getHeight(); - } - - const float gradient_height = 5.0f; - if(text_offset_y >= text_height - gradient_height && std::abs(item_height - card_height) < 1) { - const sf::Vector2f card_bottom(text_pos.x, text_height); - const sf::Color color = item_index == selected_item ? get_theme().selected_color : get_theme().card_item_background_color; - - sf::Vertex gradient_points[4]; - gradient_points[0] = sf::Vertex(card_bottom + sf::Vector2f(0.0f, -gradient_height), sf::Color(color.r, color.g, color.b, 0)); - gradient_points[1] = sf::Vertex(card_bottom + sf::Vector2f(card_max_image_size.x, -gradient_height), sf::Color(color.r, color.g, color.b, 0)); - gradient_points[2] = sf::Vertex(card_bottom + sf::Vector2f(card_max_image_size.x, 0.0f), color); - gradient_points[3] = sf::Vertex(card_bottom + sf::Vector2f(0.0f, 0.0f), color); - window.draw(gradient_points, 4, sf::Quads); - } - } + handle_item_render(pos + pos_offset, card_width, item_height, item_index); ++num_visible_items; if(first_visible_item == -1 || item_index < first_visible_item) @@ -1359,6 +1319,29 @@ namespace QuickMedia { ++item_index; } + sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, size.y)); + new_view.setViewport(sf::FloatRect(0.0f, scissor_y / (float)window_size.y, 1.0f, size.y / (float)window_size.y)); + window.setView(new_view); + + for(RenderItem &render_item : render_items) { + if(render_item.item_index == selected_item) { + item_background.set_position(round( + sf::Vector2f( + item_background_prev_pos.x, + clamp(item_background_prev_pos.y, pos.y, pos.y + size.y - item_background_prev_size.y - body_spacing[body_theme].body_padding_vertical - body_spacing[body_theme].spacing_y)))); + item_background.set_size(round(item_background_prev_size)); + item_background.set_color(get_theme().selected_color); + item_background.draw(window); + break; + } + } + + for(RenderItem &render_item : render_items) { + draw_card_item(window, render_item.body_item, render_item.pos, render_item.pos_offset, size, sf::Vector2f(window_size.x, window_size.y), render_item.item_height, scissor_y, render_item.item_index, render_item.item_thumbnail.get()); + } + + render_items.clear(); + if(row_has_selected_item) item_background_target_size = sf::Vector2f(card_width, row_max_height); } @@ -1378,15 +1361,6 @@ namespace QuickMedia { item_pos.x = std::floor(pos.x); item_pos.y = std::floor(pos.y); - if(item_index != -1 && body_theme == BODY_THEME_MODERN_SPACIOUS) { - item_background.set_size(sf::Vector2f(size.x, item_height)); - item_background.set_position(item_pos); - item_background.set_color(get_theme().shade_color); - item_background.set_band(item_background_prev_pos - pos, item_background_prev_size); - item_background.set_band_color(get_theme().selected_color); - item_background.draw(window); - } - const float padding_y = item_thumbnail ? body_spacing[body_theme].padding_y : body_spacing[body_theme].padding_y_text_only; float text_offset_x = body_spacing[body_theme].padding_x; @@ -1550,6 +1524,92 @@ namespace QuickMedia { } } + void Body::draw_card_item(sf::RenderWindow &window, std::shared_ptr &item, const sf::Vector2f &pos, const sf::Vector2f &pos_offset, const sf::Vector2f &body_size, const sf::Vector2f &window_size, float item_height, float scissor_y, int item_index, ThumbnailData *item_thumbnail) { + const sf::Vector2i thumbnail_size = get_item_thumbnail_size(item.get()); + + sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, body_size.y)); + new_view.setViewport(sf::FloatRect(0.0f, scissor_y / (float)window_size.y, 1.0f, body_size.y / (float)window_size.y)); + window.setView(new_view); + + { + float image_height = 0.0f; + if(item_thumbnail && item_thumbnail->loading_state == LoadingState::APPLIED_TO_TEXTURE && item_thumbnail->texture.getNativeHandle() != 0) { + image.setTexture(item_thumbnail->texture, true); + auto image_size = image.getTexture()->getSize(); + sf::Vector2f image_size_f(image_size.x, image_size.y); + sf::Vector2f content_size = to_vec2f(thumbnail_size); + auto new_image_size = clamp_to_size(image_size_f, content_size); + auto image_scale = get_ratio(image_size_f, new_image_size); + image.setScale(image_scale); + image.setPosition(pos + pos_offset + sf::Vector2f(card_padding_x, card_padding_y) + sf::Vector2f(card_max_image_size.x * 0.5f, 0.0f) - sf::Vector2f(new_image_size.x * 0.5f, 0.0f)); + image_height = new_image_size.y; + if(thumbnail_mask_shader && item->thumbnail_mask_type == ThumbnailMaskType::CIRCLE) { + thumbnail_mask_shader->setUniform("resolution", new_image_size); + window.draw(image, thumbnail_mask_shader); + } else if(rounded_rectangle_mask_shader) { + rounded_rectangle_mask_shader->setUniform("radius", 10.0f); + rounded_rectangle_mask_shader->setUniform("resolution", new_image_size); + window.draw(image, rounded_rectangle_mask_shader); + } else { + window.draw(image); + } + } else if(!item->thumbnail_url.empty()) { + sf::Vector2f content_size = to_vec2f(thumbnail_size); + sf::Vector2f loading_icon_size(loading_icon.getTexture()->getSize().x, loading_icon.getTexture()->getSize().y); + auto new_loading_icon_size = clamp_to_size(loading_icon_size, content_size); + loading_icon.setPosition(pos + pos_offset + sf::Vector2f(card_padding_x, card_padding_y) + sf::Vector2f(card_max_image_size.x, content_size.y) * 0.5f); + loading_icon.setScale(get_ratio(loading_icon_size, new_loading_icon_size)); + loading_icon.setRotation(elapsed_time_sec * 400.0); + window.draw(loading_icon); + image_height = content_size.y; + } + + const float text_padding = item_thumbnail ? card_image_text_padding : 0.0f; + + sf::Vector2f text_pos = sf::Vector2f(pos.x, scissor_y + body_spacing[body_theme].body_padding_vertical) + pos_offset + sf::Vector2f(card_padding_x, card_padding_y) + sf::Vector2f(0.0f, image_height + text_padding); + const float text_height = (item_height - card_padding_y * 2.0f) - image_height - text_padding; + + const float underflow_text = text_pos.y - scissor_y; + const float underflow_height = underflow_text < 0.0f ? std::max(0.0f, text_height + underflow_text) : text_height; + sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, underflow_height)); + new_view.setViewport(sf::FloatRect(0.0f, std::max(text_pos.y, scissor_y) / (float)window_size.y, 1.0f, underflow_height / (float)window_size.y)); + window.setView(new_view); + + text_pos.y = std::min(0.0f, underflow_text); + float text_offset_y = 0.0f; + if(item->author_text) { + item->author_text->setPosition(text_pos); + item->author_text->draw(window); + text_offset_y += item->author_text->getHeight(); + } + + if(item->title_text) { + item->title_text->setPosition(text_pos + sf::Vector2f(0.0f, text_offset_y)); + item->title_text->draw(window); + text_offset_y += item->title_text->getHeight(); + } + + if(item->description_text) { + item->description_text->setPosition(text_pos + sf::Vector2f(0.0f, text_offset_y)); + item->description_text->draw(window); + text_offset_y += item->description_text->getHeight(); + } + + const float gradient_height = 5.0f; + if(text_offset_y >= text_height - gradient_height && std::abs(item_height - card_height) < 1) { + const sf::Vector2f card_bottom(text_pos.x, text_height); + const sf::Color color = item_index == selected_item ? get_theme().selected_color : get_theme().card_item_background_color; + + sf::Vertex gradient_points[4]; + gradient_points[0] = sf::Vertex(card_bottom + sf::Vector2f(0.0f, -gradient_height), sf::Color(color.r, color.g, color.b, 0)); + gradient_points[1] = sf::Vertex(card_bottom + sf::Vector2f(card_max_image_size.x, -gradient_height), sf::Color(color.r, color.g, color.b, 0)); + gradient_points[2] = sf::Vertex(card_bottom + sf::Vector2f(card_max_image_size.x, 0.0f), color); + gradient_points[3] = sf::Vertex(card_bottom + sf::Vector2f(0.0f, 0.0f), color); + window.draw(gradient_points, 4, sf::Quads); + } + } + } + float Body::get_item_height(BodyItem *item, float width, bool load_texture, bool include_embedded_item, bool merge_with_previous, int item_index) { const bool rendering_card_view = card_view && card_view_enabled; sf::Vector2i content_size = get_item_thumbnail_size(item); diff --git a/src/RoundedRectangle.cpp b/src/RoundedRectangle.cpp index 4776618..fc56823 100644 --- a/src/RoundedRectangle.cpp +++ b/src/RoundedRectangle.cpp @@ -1,13 +1,17 @@ #include "../include/RoundedRectangle.hpp" #include #include +#include #include namespace QuickMedia { static const float shadow_radius = 20.0f; // Has to match the shadow offset in rounded_rectangle.glsl + static std::atomic cached_radius = 0.0f; + static std::atomic cached_resolution_x = 0.0f; + static std::atomic cached_resolution_y = 0.0f; RoundedRectangle::RoundedRectangle(sf::Vector2f size, float radius, sf::Color color, sf::Shader *rounded_rectangle_shader) : - radius(radius), pos(0.0f, 0.0f), size(size), rounded_rectangle_shader(rounded_rectangle_shader), band_color(sf::Color::Transparent) + radius(radius), pos(0.0f, 0.0f), size(size), rounded_rectangle_shader(rounded_rectangle_shader) { assert(rounded_rectangle_shader); set_color(color); @@ -44,22 +48,21 @@ namespace QuickMedia { return size; } - void RoundedRectangle::set_band(sf::Vector2f pos, sf::Vector2f size) { - band_pos = pos; - band_size = size; - } - - void RoundedRectangle::set_band_color(sf::Color color) { - band_color = color; - } - void RoundedRectangle::draw(sf::RenderTarget &target) { + const sf::Vector2f resolution = size + sf::Vector2f(shadow_radius*2.0f, shadow_radius*2.0f); + // TODO: Remove these for optimizations. Also do the same in other places where setUniform is called - rounded_rectangle_shader->setUniform("radius", radius); - rounded_rectangle_shader->setUniform("band_pos", band_pos + sf::Vector2f(shadow_radius, shadow_radius)); - rounded_rectangle_shader->setUniform("band_size", band_size); - rounded_rectangle_shader->setUniform("band_color", sf::Glsl::Vec4(band_color.r/255.0f, band_color.g/255.0f, band_color.b/255.0f, band_color.a/255.0f)); - rounded_rectangle_shader->setUniform("resolution", size + sf::Vector2f(shadow_radius*2.0f, shadow_radius*2.0f)); + if(std::abs(cached_radius - radius) > 0.01f) { + rounded_rectangle_shader->setUniform("radius", radius); + cached_radius = radius; + } + + if(std::abs(cached_resolution_x - resolution.x) > 0.01f || std::abs(cached_resolution_y - resolution.y) > 0.01f) { + rounded_rectangle_shader->setUniform("resolution", size + sf::Vector2f(shadow_radius*2.0f, shadow_radius*2.0f)); + cached_resolution_x = resolution.x; + cached_resolution_y = resolution.y; + } + target.draw(vertices, 4, sf::Quads, rounded_rectangle_shader); } } \ No newline at end of file -- cgit v1.2.3