From cc3a65bde2e480b2b07b74eeef20d9081d7f730f Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 2 Jun 2021 17:42:30 +0200 Subject: Add modern theme Join matrix room by their name instead of id if there is a name. This allows you to join rooms where the homeserver that created the room is no longer participating in the room. --- src/Body.cpp | 304 +++++++++++++++++++++++++++++--------------- src/QuickMedia.cpp | 136 ++++++++++---------- src/RoundedRectangle.cpp | 18 ++- src/SearchBar.cpp | 2 +- src/VideoPlayer.cpp | 6 +- src/plugins/FileManager.cpp | 12 +- src/plugins/Fourchan.cpp | 4 +- src/plugins/Matrix.cpp | 14 +- src/plugins/Page.cpp | 4 +- src/plugins/Youtube.cpp | 8 +- 10 files changed, 317 insertions(+), 191 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 25faa1f..7de5f09 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -12,23 +12,68 @@ #include #include -static const sf::Color front_color(32, 36, 42); -static const sf::Color back_color(33, 35, 37); -static const float spacing_y = std::floor(10.0f * QuickMedia::get_ui_scale()); -static const float padding_x = std::floor(10.0f * QuickMedia::get_ui_scale()); -static const float image_padding_x = std::floor(5.0f * QuickMedia::get_ui_scale()); -static const float padding_y = std::floor(5.0f * QuickMedia::get_ui_scale()); -static const float embedded_item_padding_y = std::floor(0.0f * QuickMedia::get_ui_scale()); - -static const float reaction_background_padding_x = std::floor(7.0f * QuickMedia::get_ui_scale()); -static const float reaction_background_padding_y = std::floor(3.0f * QuickMedia::get_ui_scale()); -static const float reaction_spacing_x = std::floor(5.0f * QuickMedia::get_ui_scale()); -static const float reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_scale()); -static const int embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); +struct BodySpacing { + float spacing_y = 0.0f; + float padding_x = 0.0f; + float image_padding_x = 0.0f; + float padding_y = 0.0f; + float padding_y_text_only = 0.0f; + float embedded_item_padding_y = 0.0f; + float body_padding_horizontal = 0.0f; + float body_padding_vertical = 0.0f; + + float reaction_background_padding_x = 0.0f; + float reaction_background_padding_y = 0.0f; + float reaction_spacing_x = 0.0f; + float reaction_padding_y = 0.0f; + float embedded_item_font_size = 0.0f; +}; + +static BodySpacing body_spacing[2]; +static bool themes_initialized = false; namespace QuickMedia { - static float clamp(float value, float min, float max) { - return std::min(max, std::max(min, value)); + static void init_body_theme_minimal() { + body_spacing[BODY_THEME_MINIMAL].spacing_y = std::floor(10.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].padding_x = std::floor(10.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].image_padding_x = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].padding_y = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].padding_y_text_only = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].embedded_item_padding_y = std::floor(0.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].body_padding_horizontal = std::floor(10.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].body_padding_vertical = std::floor(10.0f * QuickMedia::get_ui_scale()); + + body_spacing[BODY_THEME_MINIMAL].reaction_background_padding_x = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].reaction_background_padding_y = std::floor(3.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].reaction_spacing_x = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); + } + + static void init_body_theme_modern_spacious() { + body_spacing[BODY_THEME_MODERN_SPACIOUS].spacing_y = std::floor(20.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].padding_x = std::floor(20.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].image_padding_x = std::floor(15.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].padding_y = std::floor(15.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].padding_y_text_only = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].embedded_item_padding_y = std::floor(0.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].body_padding_horizontal = std::floor(20.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].body_padding_vertical = std::floor(20.0f * QuickMedia::get_ui_scale()); + + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_background_padding_x = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_background_padding_y = std::floor(3.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_spacing_x = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); + } + + static void init_body_themes() { + if(themes_initialized) + return; + + init_body_theme_minimal(); + init_body_theme_modern_spacious(); + themes_initialized = true; } BodyItem::BodyItem(std::string _title) : @@ -104,25 +149,27 @@ namespace QuickMedia { reactions.push_back(std::move(reaction)); } - Body::Body(Program *program, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader) : - progress_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), - replies_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), - embedded_item_load_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), embedded_item_font_size), + Body::Body(BodyTheme body_theme, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader, sf::Shader *rounded_rectangle_mask_shader) : draw_thumbnails(true), - line_separator_color(sf::Color(32, 37, 43, 255)), body_item_render_callback(nullptr), thumbnail_mask_shader(nullptr), - program(program), + body_theme(body_theme), selected_item(0), prev_selected_item(0), loading_icon(loading_icon_texture), + progress_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), + replies_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), num_visible_items(0), top_cut_off(false), bottom_cut_off(false), item_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(55, 60, 68), rounded_rectangle_shader), - reaction_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(33, 37, 44), rounded_rectangle_shader) + reaction_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(33, 37, 44), rounded_rectangle_shader), + rounded_rectangle_mask_shader(rounded_rectangle_mask_shader) { assert(rounded_rectangle_shader); + assert(rounded_rectangle_mask_shader); + init_body_themes(); + embedded_item_load_text = sf::Text("", *FontLoader::get_font(FontLoader::FontType::LATIN), body_spacing[body_theme].embedded_item_font_size); progress_text.setFillColor(sf::Color::White); replies_text.setFillColor(sf::Color(129, 162, 190)); thumbnail_max_size.x = 250; @@ -417,6 +464,19 @@ namespace QuickMedia { return false; } + void Body::draw_drop_shadow(sf::RenderWindow &window) { + if(!show_drop_shadow) + return; + + const float height = 5.0f; + sf::Vertex gradient_points[4]; + gradient_points[0] = sf::Vertex(body_pos + sf::Vector2f(0.0f, 0.0f), sf::Color(21, 25, 30)); + gradient_points[1] = sf::Vertex(body_pos + sf::Vector2f(body_size.x, 0.0f), sf::Color(21, 25, 30)); + gradient_points[2] = sf::Vertex(body_pos + sf::Vector2f(body_size.x, height), sf::Color(0, 0, 0, 0)); + gradient_points[3] = sf::Vertex(body_pos + sf::Vector2f(0.0f, height), sf::Color(0, 0, 0, 0)); + window.draw(gradient_points, 4, sf::Quads); + } + void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size) { draw(window, pos, size, Json::Value::nullSingleton()); } @@ -430,10 +490,20 @@ namespace QuickMedia { items_dirty = DirtyState::FALSE; } + bool body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f; + if(body_size_changed) + body_size = size; + body_pos = pos; const float scissor_y = pos.y; pos.y = 0.0f; + pos.x += body_spacing[body_theme].body_padding_horizontal; + if(attach_side == AttachSide::TOP) + pos.y += body_spacing[body_theme].body_padding_vertical; + + 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 > 0.01666f) frame_time = 0.01666f; @@ -448,10 +518,6 @@ namespace QuickMedia { prev_selected_item = selected_item; } - bool body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f; - if(body_size_changed) - body_size = size; - elapsed_time_sec = draw_timer.getElapsedTime().asSeconds(); const int prev_num_visible_items = num_visible_items; @@ -483,6 +549,8 @@ namespace QuickMedia { mouse_left_clicked = false; clicked_body_item = nullptr; + + draw_drop_shadow(window); return; } @@ -540,7 +608,7 @@ namespace QuickMedia { double dist_to_target; if(body_swipe_move_right) - dist_to_target = body_size.x - body_swipe_x; + dist_to_target = (body_size.x - body_spacing[body_theme].body_padding_horizontal) - body_swipe_x; else dist_to_target = 0.0f - body_swipe_x; body_swipe_x += (dist_to_target * std::min(1.0f, frame_time * move_speed)); @@ -553,7 +621,7 @@ namespace QuickMedia { const int selected_prev_item = get_previous_visible_item(selected_item); const bool selected_merge_with_previous = selected_prev_item != -1 && body_item_merge_handler && body_item_merge_handler(items[selected_prev_item].get(), items[selected_item].get()); get_item_height(items[selected_item].get(), size.x, true, true, selected_merge_with_previous, selected_item); - selected_item_fits_in_body = items[selected_item]->last_loaded_height < body_size.y; + selected_item_fits_in_body = items[selected_item]->last_loaded_height < size.y; if(selected_item_fits_in_body) selected_scrolled = 0.0f; @@ -572,24 +640,27 @@ namespace QuickMedia { const float speed = 30.0f; - const float item_background_prev_height = item_background.get_size().y; const float item_background_height_diff = item_background_target_height - item_background_prev_height; const float item_background_height_speed = instant_move ? 1000.0f : speed; const float item_background_new_height = item_background_prev_height + (item_background_height_diff * std::min(1.0f, frame_time * item_background_height_speed)); item_background.set_size(sf::Vector2f(size.x, item_background_new_height)); + item_background_prev_height = item_background_new_height; - const float item_background_prev_pos_y = item_background.get_position().y; const float item_background_pos_diff = item_background_target_pos_y - item_background_prev_pos_y; const float item_background_move_speed = instant_move ? 1000.0f : speed; float item_background_new_pos_y = item_background_prev_pos_y + (item_background_pos_diff * std::min(1.0f, frame_time * item_background_move_speed)); if(selected_item_fits_in_body) { - item_background_new_pos_y = std::min(item_background_new_pos_y, body_size.y - item_background_new_height - spacing_y); + item_background_new_pos_y = std::min(item_background_new_pos_y, size.y - item_background_new_height - body_spacing[body_theme].spacing_y); item_background_new_pos_y = std::max(item_background_new_pos_y, 0.0f); } item_background.set_position(sf::Vector2f(pos.x, item_background_new_pos_y)); + item_background_prev_pos_y = item_background_new_pos_y; - if(prev_num_visible_items > 0 && render_selected_item_bg) + if(prev_num_visible_items > 0 && render_selected_item_bg && body_theme == BODY_THEME_MINIMAL) { + item_background.set_color(sf::Color(55, 60, 68)); + item_background.set_band(0.0f, 0.0f); item_background.draw(window); + } int index; if(attach_side == AttachSide::TOP) { @@ -603,11 +674,11 @@ namespace QuickMedia { } else { if(page_scroll < 0.0) page_scroll = 0.0; - pos.y += body_size.y; + pos.y += size.y; pos.y += page_scroll; index = get_previous_visible_item(num_items); - if(pos.y + selected_scrolled < body_size.y) + if(pos.y + selected_scrolled < size.y) selected_scrolled = 0.0f; } @@ -633,7 +704,7 @@ namespace QuickMedia { const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, item); if(attach_side == AttachSide::TOP && merge_with_previous) - pos.y -= spacing_y; + pos.y -= body_spacing[body_theme].spacing_y; get_item_height(item, size.x, false, true, merge_with_previous, index); const float item_height_diff = item->last_loaded_height - item->current_loaded_height; @@ -645,7 +716,7 @@ namespace QuickMedia { if(attach_side == AttachSide::TOP) top_y = pos.y; else - top_y = pos.y - (item->current_loaded_height + spacing_y); + top_y = pos.y - (item->current_loaded_height + body_spacing[body_theme].spacing_y); if(top_y < 0.0f) { top_cut_off = true; @@ -653,30 +724,30 @@ namespace QuickMedia { selected_line_top_visible = false; } - if(top_y + item->current_loaded_height > body_size.y) { + if(top_y + item->current_loaded_height > size.y) { bottom_cut_off = true; if(index == selected_item) selected_line_bottom_visible = false; } - const bool is_item_visible_in_body = top_y + item->current_loaded_height >= 0.0f && top_y <= body_size.y; + const bool is_item_visible_in_body = top_y + item->current_loaded_height >= 0.0f && top_y <= size.y; if(is_item_visible_in_body || index == selected_item) { get_item_height(item, size.x, true, true, merge_with_previous, index); const float item_height_diff = item->last_loaded_height - item->current_loaded_height; const float add_height = item_height_diff * std::min(1.0, frame_time * height_move_speed); item->current_loaded_height += add_height; if(attach_side == AttachSide::BOTTOM) - pos.y -= (item->current_loaded_height + spacing_y); + pos.y -= (item->current_loaded_height + body_spacing[body_theme].spacing_y); //page_scroll += add_height; - //const float top_y_clamped = clamp(pos.y, 0.0f, body_size.y); - //const float bottom_y_clamped = std::min(pos.y + item->current_loaded_height, body_size.y); + //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 > body_size.y) - // offset_y = body_size.y - pos.y; + //else if(pos.y > size.y) + // offset_y = size.y - pos.y; //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)); @@ -692,12 +763,12 @@ namespace QuickMedia { last_visible_item = index; if(attach_side == AttachSide::TOP) - pos.y += (item->current_loaded_height + spacing_y); + pos.y += (item->current_loaded_height + body_spacing[body_theme].spacing_y); } else { if(attach_side == AttachSide::TOP) - pos.y += (item->current_loaded_height + spacing_y); + pos.y += (item->current_loaded_height + body_spacing[body_theme].spacing_y); else - pos.y -= (item->current_loaded_height + spacing_y); + pos.y -= (item->current_loaded_height + body_spacing[body_theme].spacing_y); if(item->keep_alive_frames == 0) { clear_body_item_cache(item); @@ -710,7 +781,7 @@ namespace QuickMedia { } if(attach_side == AttachSide::BOTTOM && merge_with_previous) - pos.y += spacing_y; + pos.y += body_spacing[body_theme].spacing_y; if(attach_side == AttachSide::TOP) { prev_body_item = item; @@ -721,17 +792,19 @@ namespace QuickMedia { } window.setView(prev_view); + draw_drop_shadow(window); // TODO: Move up where scroll is limited? then we wont delay this by 1 frame creating a small scroll overflow only in the opposite direction of attach side. // Also take |selected_scrolled| into consideration + // Limit scroll in the opposide direction of attach side, since the scroll is already limited for the attach side above (with a simple check) if(attach_side == AttachSide::TOP) { const float body_total_height = pos.y - pos_y_start; - if(top_cut_off && !bottom_cut_off && body_total_height > body_size.y) - page_scroll = -(body_total_height - body_size.y); + if(top_cut_off && !bottom_cut_off && body_total_height > (size.y - body_spacing[body_theme].body_padding_vertical)) + page_scroll = -(body_total_height - (size.y - body_spacing[body_theme].body_padding_vertical)); } else { const float body_total_height = pos_y_start - pos.y; - if(bottom_cut_off && !top_cut_off && body_total_height > body_size.y) - page_scroll = (body_total_height - body_size.y); + if(bottom_cut_off && !top_cut_off && body_total_height > size.y) + page_scroll = (body_total_height - size.y); } mouse_left_clicked = false; @@ -745,8 +818,8 @@ namespace QuickMedia { if(is_touch_enabled()) return; - const float item_target_top_diff = item_background_target_pos_y - selected_scrolled; - const float item_target_bottom_diff = (item_background_target_pos_y - selected_scrolled + item_background_target_height + spacing_y) - body_size.y; + const float item_target_top_diff = item_background_target_pos_y - selected_scrolled - body_spacing[body_theme].body_padding_vertical; + const float item_target_bottom_diff = (item_background_target_pos_y - selected_scrolled + item_background_target_height + body_spacing[body_theme].spacing_y) - size.y; if(item_target_top_diff < 0.0f || !selected_item_fits_in_body) { //extra_scroll_target -= item_target_top_diff; stuck_direction = StuckDirection::TOP; @@ -900,7 +973,7 @@ namespace QuickMedia { void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size, bool include_embedded_item, bool is_embedded) { item->keep_alive_frames = 3; get_item_height(item, size.x, true, false, false, -1); - draw_item(window, item, pos, size, size.y + spacing_y, -1, Json::Value::nullSingleton(), include_embedded_item); + draw_item(window, item, pos, size, size.y + body_spacing[body_theme].spacing_y, -1, Json::Value::nullSingleton(), include_embedded_item); } // TODO: Better message? maybe fallback to the reply message, or message status (such as message redacted) @@ -936,6 +1009,18 @@ namespace QuickMedia { } } + static sf::Color interpolate_colors(sf::Color source, sf::Color target, double progress) { + int diff_r = (int)target.r - (int)source.r; + int diff_g = (int)target.g - (int)source.g; + int diff_b = (int)target.b - (int)source.b; + int diff_a = (int)target.a - (int)source.a; + return sf::Color( + source.r + diff_r * progress, + source.g + diff_g * progress, + source.b + diff_b * progress, + source.a + diff_a * progress); + } + 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, bool merge_with_previous) { sf::Vector2i thumbnail_size = get_item_thumbnail_size(item); std::shared_ptr item_thumbnail; @@ -951,7 +1036,18 @@ namespace QuickMedia { item_pos.x = std::floor(pos.x); item_pos.y = std::floor(pos.y); - float text_offset_x = padding_x; + 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(sf::Color(33, 37, 44)); + item_background.set_band(item_background_prev_pos_y - pos.y, item_background_prev_height); + item_background.set_band_color(sf::Color(55, 60, 68)); + 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; if(item_thumbnail && !merge_with_previous) { // TODO: Verify if this is safe. The thumbnail is being modified in another thread if(item_thumbnail->loading_state == LoadingState::APPLIED_TO_TEXTURE && item_thumbnail->texture.getNativeHandle() != 0) { @@ -962,14 +1058,18 @@ namespace QuickMedia { 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(item_pos + sf::Vector2f(image_padding_x, padding_y)); + image.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_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); } - text_offset_x += image_padding_x + new_image_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + new_image_size.x; // We want the next image fallback to have the same size as the successful image rendering, because its likely the image fallback will have the same size (for example thumbnails on youtube) //image_fallback.setSize(sf::Vector2f(width_ratio * image_size.x, height_ratio * image_size.y)); } else if(!item->thumbnail_url.empty()) { @@ -982,31 +1082,33 @@ namespace QuickMedia { // TODO: Cache circle shape sf::CircleShape circle_shape(content_size.x * 0.5f); circle_shape.setFillColor(fallback_color); - circle_shape.setPosition(item_pos + sf::Vector2f(image_padding_x, padding_y)); + circle_shape.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y)); window.draw(circle_shape); } else { image_fallback.setSize(content_size); image_fallback.setFillColor(fallback_color); - image_fallback.setPosition(item_pos + sf::Vector2f(image_padding_x, padding_y)); + image_fallback.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y)); window.draw(image_fallback); } 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(item_pos + sf::Vector2f(image_padding_x, padding_y) + (content_size * 0.5f)); + loading_icon.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y) + (content_size * 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); - text_offset_x += image_padding_x + content_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + content_size.x; } } else if(item->thumbnail_size.x > 0) { - text_offset_x += image_padding_x + thumbnail_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + thumbnail_size.x; } - const float timestamp_text_y = std::floor(item_pos.y + padding_y - std::floor(6.0f * get_ui_scale())); + const float text_offset_y = std::floor(8.0f * get_ui_scale()); + + const float timestamp_text_y = std::floor(item_pos.y + padding_y - text_offset_y); if(item->author_text && !merge_with_previous) { - item->author_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 6.0f * get_ui_scale())); - item->author_text->setMaxWidth(size.x - text_offset_x - image_padding_x); + item->author_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - text_offset_y)); + item->author_text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); item->author_text->draw(window); sf::Vector2f replies_text_pos = item->author_text->getPosition() + sf::Vector2f(0.0f, 5.0f); @@ -1027,20 +1129,20 @@ namespace QuickMedia { if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { const float border_width = 4.0f; - const float embedded_item_width = std::floor(size.x - text_offset_x - border_width - padding_x); - float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), embedded_item_width, true, false) : ((embedded_item_font_size + 5.0f) + embedded_item_padding_y * 2.0f); + const float embedded_item_width = std::floor(size.x - text_offset_x - border_width - body_spacing[body_theme].padding_x); + float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), embedded_item_width, true, false) : ((body_spacing[body_theme].embedded_item_font_size + 5.0f) + body_spacing[body_theme].embedded_item_padding_y * 2.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)); + border_left.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + body_spacing[body_theme].embedded_item_padding_y + 2.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_pos(std::floor(item_pos.x + text_offset_x + border_width + body_spacing[body_theme].padding_x), std::floor(item_pos.y + body_spacing[body_theme].embedded_item_padding_y + 6.0f)); sf::Vector2f embedded_item_size(embedded_item_width, embedded_item_height); draw_item(window, item->embedded_item.get(), embedded_item_pos, embedded_item_size, false, true); } 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_font_size + 5.0f) * 0.5f + 4.0f)); + embedded_item_load_text.setPosition(std::floor(item_pos.x + text_offset_x + border_width + body_spacing[body_theme].padding_x), std::floor(item_pos.y + embedded_item_height * 0.5f - (body_spacing[body_theme].embedded_item_font_size + 5.0f) * 0.5f + 6.0f)); window.draw(embedded_item_load_text); } item_pos.y += embedded_item_height + 4.0f; @@ -1050,47 +1152,47 @@ namespace QuickMedia { //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->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - std::floor(6.0f * get_ui_scale()))); - item->title_text->setMaxWidth(size.x - text_offset_x - image_padding_x); + item->title_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - text_offset_y)); + item->title_text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); item->title_text->draw(window); item_pos.y += item->title_text->getHeight() - 2.0f + std::floor(3.0f * get_ui_scale()); } if(item->description_text) { float height_offset = 0.0f; - item->description_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - std::floor(6.0f * get_ui_scale()) + height_offset)); - item->description_text->setMaxWidth(size.x - text_offset_x - image_padding_x); + item->description_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - text_offset_y) + height_offset); + item->description_text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); item->description_text->draw(window); item_pos.y += item->description_text->getHeight() - 2.0f; } if(!item->reactions.empty() && include_embedded_item) { float reaction_offset_x = 0.0f; - item_pos.y += reaction_padding_y; + item_pos.y += body_spacing[body_theme].reaction_padding_y; float reaction_max_height = 0.0f; // TODO: Fix first row wrap-around for(int i = 0; i < item->reactions.size(); ++i) { auto &reaction = item->reactions[i]; - reaction.text->setMaxWidth(size.x - text_offset_x - image_padding_x); + reaction.text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); reaction.text->updateGeometry(); reaction_max_height = std::max(reaction_max_height, reaction.text->getHeight()); - reaction.text->setPosition(std::floor(item_pos.x + text_offset_x + reaction_offset_x + reaction_background_padding_x), std::floor(item_pos.y + padding_y - 4.0f + reaction_background_padding_y)); + reaction.text->setPosition(std::floor(item_pos.x + text_offset_x + reaction_offset_x + body_spacing[body_theme].reaction_background_padding_x), std::floor(item_pos.y + padding_y - 4.0f + body_spacing[body_theme].reaction_background_padding_y)); reaction_background.set_position(sf::Vector2f(std::floor(item_pos.x + text_offset_x + reaction_offset_x), std::floor(item_pos.y + padding_y))); - reaction_background.set_size(sf::Vector2f(reaction.text->getWidth() + reaction_background_padding_x * 2.0f, reaction.text->getHeight() + reaction_background_padding_y * 2.0f)); + reaction_background.set_size(sf::Vector2f(reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f, reaction.text->getHeight() + body_spacing[body_theme].reaction_background_padding_y * 2.0f)); reaction_background.draw(window); - reaction_offset_x += reaction.text->getWidth() + reaction_background_padding_x * 2.0f + reaction_spacing_x; + reaction_offset_x += reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f + body_spacing[body_theme].reaction_spacing_x; reaction.text->draw(window); - if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + reaction_background_padding_x * 2.0f > size.x && i < (int)item->reactions.size() - 1) { + if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f > size.x && i < (int)item->reactions.size() - 1) { reaction_offset_x = 0.0f; - item_pos.y += reaction.text->getHeight() + reaction_padding_y + std::floor(6.0f * get_ui_scale()); + item_pos.y += reaction.text->getHeight() + body_spacing[body_theme].reaction_padding_y + std::floor(8.0f * get_ui_scale()); reaction_max_height = reaction.text->getHeight(); } } - item_pos.y += reaction_max_height + reaction_padding_y; + item_pos.y += reaction_max_height + body_spacing[body_theme].reaction_padding_y; } if(item_index == selected_item && item->timestamp_text) { - item->timestamp_text->setPosition(std::floor(item_pos.x + size.x - item->timestamp_text->getLocalBounds().width - padding_x), timestamp_text_y + 8.0f); + item->timestamp_text->setPosition(std::floor(item_pos.x + size.x - item->timestamp_text->getLocalBounds().width - body_spacing[body_theme].padding_x), timestamp_text_y + 8.0f); window.draw(*item->timestamp_text); } @@ -1106,7 +1208,7 @@ 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), timestamp_text_y + std::floor(6.0f * get_ui_scale())); + progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - body_spacing[body_theme].padding_x), timestamp_text_y + std::floor(8.0f * get_ui_scale())); window.draw(progress_text); } } @@ -1116,8 +1218,10 @@ namespace QuickMedia { sf::Vector2i content_size = get_item_thumbnail_size(item); float image_height = 0.0f; - float text_offset_x = padding_x; + float text_offset_x = body_spacing[body_theme].padding_x; + bool has_thumbnail = false; if(draw_thumbnails && load_texture && !item->thumbnail_url.empty() && !merge_with_previous) { + has_thumbnail = true; std::shared_ptr item_thumbnail = AsyncImageLoader::get_instance().get_thumbnail(item->thumbnail_url, item->thumbnail_is_local, content_size); content_size = clamp_to_size_x(content_size, sf::Vector2i(width, content_size.y)); image_height = content_size.y; @@ -1136,19 +1240,19 @@ namespace QuickMedia { sf::Vector2f image_size_f(image_size.x, image_size.y); auto new_image_size = clamp_to_size(image_size_f, to_vec2f(content_size)); image_height = new_image_size.y; - text_offset_x += image_padding_x + new_image_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + new_image_size.x; } else { - text_offset_x += image_padding_x + content_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + content_size.x; } } else if(item->thumbnail_size.x > 0) { - text_offset_x += image_padding_x + content_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + content_size.x; // TODO: Fix. This makes the body item have incorrect position when loading and if the item is merge_with_previous? and has an embedded item //if(!merge_with_previous) // image_height = content_size.y; } if(load_texture) - update_dirty_state(item, width - text_offset_x - image_padding_x); + update_dirty_state(item, width - text_offset_x - body_spacing[body_theme].image_padding_x); float item_height = 0.0f; if(item->title_text) { @@ -1159,9 +1263,9 @@ namespace QuickMedia { } if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { if(item->embedded_item) - item_height += (get_item_height(item->embedded_item.get(), width, load_texture, false) + 4.0f + embedded_item_padding_y * 2.0f); + item_height += (get_item_height(item->embedded_item.get(), width, load_texture, false) + 6.0f + body_spacing[body_theme].embedded_item_padding_y * 2.0f); else - item_height += ((embedded_item_font_size + 5.0f) + 4.0f + embedded_item_padding_y * 2.0f); + item_height += ((body_spacing[body_theme].embedded_item_font_size + 5.0f) + 6.0f + body_spacing[body_theme].embedded_item_padding_y * 2.0f); } if(item->description_text) { item_height += item->description_text->getHeight() - 2.0f; @@ -1169,23 +1273,25 @@ namespace QuickMedia { if(!item->reactions.empty() && include_embedded_item) { float reaction_offset_x = 0.0f; - item_height += reaction_padding_y; + item_height += body_spacing[body_theme].reaction_padding_y; float reaction_max_height = 0.0f; for(int i = 0; i < item->reactions.size(); ++i) { auto &reaction = item->reactions[i]; - reaction.text->setMaxWidth(width - text_offset_x - image_padding_x); + reaction.text->setMaxWidth(width - text_offset_x - body_spacing[body_theme].image_padding_x); reaction.text->updateGeometry(); reaction_max_height = std::max(reaction_max_height, reaction.text->getHeight()); - reaction_offset_x += reaction.text->getWidth() + reaction_background_padding_x * 2.0f + reaction_spacing_x; - if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + reaction_background_padding_x * 2.0f > width && i < (int)item->reactions.size() - 1) { + reaction_offset_x += reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f + body_spacing[body_theme].reaction_spacing_x; + if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f > width && i < (int)item->reactions.size() - 1) { reaction_offset_x = 0.0f; - item_height += reaction.text->getHeight() + reaction_padding_y + std::floor(6.0f * get_ui_scale()); + item_height += reaction.text->getHeight() + body_spacing[body_theme].reaction_padding_y + std::floor(8.0f * get_ui_scale()); reaction_max_height = reaction.text->getHeight(); } } - item_height += reaction_max_height + reaction_padding_y; + item_height += reaction_max_height + body_spacing[body_theme].reaction_padding_y; } + const float padding_y = has_thumbnail ? body_spacing[body_theme].padding_y : body_spacing[body_theme].padding_y_text_only; + item_height = std::max(item_height, image_height); item_height += (padding_y * 2.0f); @@ -1208,10 +1314,6 @@ namespace QuickMedia { return item_height; } - float Body::get_spacing_y() const { - return spacing_y; - } - // TODO: Support utf-8 case insensitive find static bool string_find_fuzzy_case_insensitive(const std::string &str, const std::string &substr) { if(str.empty()) return false; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 42b7106..c9094e3 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -149,6 +149,7 @@ static int get_monitor_max_hz(Display *display) { static int get_largest_monitor_height(Display *display) { int max_height = 0; + for_each_active_monitor_output(display, [&max_height](const XRRCrtcInfo *crtc_info, const XRRModeInfo*) { // Need to get the min of width or height because we want to get the smallest size for monitors in portrait mode, for mobile devices such as pinephone int width_or_height = std::min((int)crtc_info->width, (int)crtc_info->height); @@ -156,8 +157,9 @@ static int get_largest_monitor_height(Display *display) { }); if(max_height == 0) - return DefaultScreenOfDisplay(display)->height; - return std::max(max_height, 480); + max_height = DefaultScreenOfDisplay(display)->height; + + return std::max(max_height, 240); } static void get_screen_resolution(Display *display, int *width, int *height) { @@ -587,8 +589,10 @@ namespace QuickMedia { void Program::init(Window parent_window, std::string &program_path) { disp = XOpenDisplay(NULL); - if (!disp) - throw std::runtime_error("Failed to open display to X11 server"); + if (!disp) { + fprintf(stderr, "Failed to open display to X11 server\n"); + abort(); + } XSetErrorHandler(x_error_handler); XSetIOErrorHandler(x_io_error_handler); @@ -610,8 +614,10 @@ namespace QuickMedia { InputOutput, DefaultVisual(disp, screen), 0, nullptr); - if(!x11_window) - throw std::runtime_error("Failed to create window"); + if(!x11_window) { + fprintf(stderr, "Failed to create window\n"); + abort(); + } if(strcmp(plugin_name, "download") == 0) { XSizeHints *size_hints = XAllocSizeHints(); @@ -656,6 +662,11 @@ namespace QuickMedia { fprintf(stderr, "Failed to load %s/shaders/rounded_rectangle.glsl\n", resources_root.c_str()); abort(); } + + if(!rounded_rectangle_mask_shader.loadFromFile(resources_root + "shaders/rounded_rectangle_mask.glsl", sf::Shader::Type::Fragment)) { + fprintf(stderr, "Failed to load %s/shaders/rounded_rectangle_mask.glsl\n", resources_root.c_str()); + abort(); + } } if(!loading_icon.loadFromFile(resources_root + "images/loading_icon.png")) { @@ -691,14 +702,20 @@ namespace QuickMedia { */ fprintf(stderr, "Monitor hz: %d\n", monitor_hz); - if(create_directory_recursive(get_cache_dir().join("media")) != 0) - throw std::runtime_error("Failed to create media directory"); + if(create_directory_recursive(get_cache_dir().join("media")) != 0) { + fprintf(stderr, "Failed to create media directory\n"); + abort(); + } - if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0) - throw std::runtime_error("Failed to create thumbnails directory"); + if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0) { + fprintf(stderr, "Failed to create thumbnails directory\n"); + abort(); + } - //if(create_directory_recursive(get_storage_dir().join("file-manager")) != 0) - // throw std::runtime_error("Failed to create file-manager directory"); + //if(create_directory_recursive(get_storage_dir().join("file-manager")) != 0) { + // fprintf(stderr, "Failed to create file-manager directory\n"); + // abort(); + //} const char *qm_phone_factor = getenv("QM_PHONE_FACTOR"); if(qm_phone_factor && atoi(qm_phone_factor) == 1) @@ -1387,13 +1404,7 @@ namespace QuickMedia { } static void get_body_dimensions(const sf::Vector2f &window_size, SearchBar *search_bar, sf::Vector2f &body_pos, sf::Vector2f &body_size, bool has_tabs = false) { - float body_padding_horizontal = 10.0f; - float body_padding_vertical = std::floor(10.0f); - float body_width = window_size.x - body_padding_horizontal * 2.0f; - /*if(body_width <= 480.0f) { - body_width = window_size.x; - body_padding_horizontal = 10.0f; - }*/ + const float body_width = window_size.x; float tab_h = Tabs::get_shade_height(); if(!search_bar) @@ -1403,12 +1414,12 @@ namespace QuickMedia { tab_h = 0.0f; float search_bottom = search_bar ? search_bar->getBottomWithoutShadow() : 0.0f; - body_pos = sf::Vector2f(body_padding_horizontal, search_bottom + body_padding_vertical + tab_h); - body_size = sf::Vector2f(body_width, window_size.y - search_bottom - body_padding_vertical - tab_h); + body_pos = sf::Vector2f(0.0f, search_bottom + tab_h); + body_size = sf::Vector2f(body_width, window_size.y - search_bottom - tab_h); } - std::unique_ptr Program::create_body() { - auto body = std::make_unique(this, loading_icon, &rounded_rectangle_shader); + std::unique_ptr Program::create_body(bool plain_text_list) { + auto body = std::make_unique(plain_text_list ? BODY_THEME_MINIMAL : BODY_THEME_MODERN_SPACIOUS, loading_icon, &rounded_rectangle_shader, &rounded_rectangle_mask_shader); body->thumbnail_mask_shader = &circle_mask_shader; return body; } @@ -1748,6 +1759,7 @@ namespace QuickMedia { current_page = PageType::CHAT; current_chat_room = matrix->get_room_by_id(tmp_matrix_chat_page->room_id); + rooms_page->body->show_drop_shadow = false; while(window.isOpen() && current_chat_room) { auto matrix_chat_page = std::make_unique(this, current_chat_room->id, rooms_page); bool move_room = chat_page(matrix_chat_page.get(), current_chat_room); @@ -1761,6 +1773,7 @@ namespace QuickMedia { current_chat_room = matrix->get_room_by_id(selected_item->url); } + rooms_page->body->show_drop_shadow = true; room_list_body->body_item_select_callback = [&submit_handler](BodyItem *body_item) { submit_handler(body_item->get_title()); @@ -2213,7 +2226,7 @@ namespace QuickMedia { unsigned long num_items = 0; unsigned long bytes_after = 0; unsigned char *properties = nullptr; - if(XGetWindowProperty(display, window, wm_state_atom, 0, 1024, False, XA_ATOM, &type, &format, &num_items, &bytes_after, &properties) != Success) { + if(XGetWindowProperty(display, window, wm_state_atom, 0, 1024, False, XA_ATOM, &type, &format, &num_items, &bytes_after, &properties) != Success || !properties) { fprintf(stderr, "Failed to get window wm state property\n"); return false; } @@ -3405,7 +3418,7 @@ namespace QuickMedia { bool frame_skip_text_entry = false; comment_input.on_submit_callback = [&frame_skip_text_entry, &comment_input, &post_comment_future, &navigation_stage, &request_new_google_captcha_challenge, &comment_to_post, &captcha_post_id, &captcha_solved_time, &post_comment, &selected_file_for_upload, &thread_page](std::string text) -> bool { - if(text.empty()) + if(text.empty() && selected_file_for_upload.empty()) return false; comment_input.set_editable(false); @@ -3737,19 +3750,13 @@ namespace QuickMedia { comment_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x)); comment_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), chat_input_padding_y)); - float body_padding_horizontal = 10.0f; - float body_padding_vertical = std::floor(10.0f); - float body_width = window_size.x - body_padding_horizontal * 2.0f; - /*if(body_width <= 480.0f) { - body_width = window_size.x; - body_padding_horizontal = 0.0f; - }*/ + const float body_width = window_size.x; comment_input_shade.setSize(sf::Vector2f(window_size.x, chat_input_height_full)); comment_input_shade.setPosition(0.0f, 0.0f); - body_pos = sf::Vector2f(body_padding_horizontal, comment_input_shade.getSize().y + body_padding_vertical); - body_size = sf::Vector2f(body_width, window_size.y - comment_input_shade.getSize().y - body_padding_vertical); + body_pos = sf::Vector2f(0.0f, comment_input_shade.getSize().y); + body_size = sf::Vector2f(body_width, window_size.y - comment_input_shade.getSize().y); logo_sprite.setPosition(logo_padding_x, chat_input_padding_y); file_to_upload_sprite.setPosition(logo_sprite.getPosition() + sf::Vector2f(0.0f, logo_size.y + logo_file_to_upload_spacing)); @@ -4127,26 +4134,27 @@ namespace QuickMedia { std::vector tabs; ChatTab pinned_tab; - pinned_tab.body = create_body(); + pinned_tab.body = create_body(true); pinned_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; pinned_tab.body->attach_side = AttachSide::BOTTOM; - pinned_tab.body->line_separator_color = sf::Color::Transparent; tabs.push_back(std::move(pinned_tab)); ChatTab messages_tab; - messages_tab.body = create_body(); + messages_tab.body = create_body(true); messages_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; messages_tab.body->attach_side = AttachSide::BOTTOM; - messages_tab.body->line_separator_color = sf::Color::Transparent; tabs.push_back(std::move(messages_tab)); ChatTab users_tab; - users_tab.body = create_body(); + users_tab.body = create_body(true); users_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; users_tab.body->attach_side = AttachSide::TOP; - users_tab.body->line_separator_color = sf::Color::Transparent; tabs.push_back(std::move(users_tab)); + for(ChatTab &tab : tabs) { + tab.body->show_drop_shadow = false; + } + Tabs ui_tabs(&rounded_rectangle_shader, is_touch_enabled() ? sf::Color::Transparent : back_color); const int PINNED_TAB_INDEX = ui_tabs.add_tab("Pinned messages (0)"); const int MESSAGES_TAB_INDEX = ui_tabs.add_tab("Messages"); @@ -4168,7 +4176,7 @@ namespace QuickMedia { bool setting_read_marker = false; sf::Clock start_typing_timer; - const double typing_timeout_seconds = 3.0; + const double typing_timeout_seconds = 5.0; bool typing = false; MessageQueue typing_state_queue; @@ -4425,7 +4433,7 @@ namespace QuickMedia { ui_tabs.set_text(PINNED_TAB_INDEX, "Pinned messages (" + std::to_string(tabs[PINNED_TAB_INDEX].body->items.size()) + ")"); }; - Body url_selection_body(this, loading_icon, &rounded_rectangle_shader); + Body url_selection_body(BODY_THEME_MINIMAL, loading_icon, &rounded_rectangle_shader, &rounded_rectangle_mask_shader); std::unordered_set fetched_messages_set; auto filter_existing_messages = [&fetched_messages_set](Messages &messages) { @@ -5219,9 +5227,6 @@ namespace QuickMedia { tabs[i].body->on_top_reached = on_top_reached; } - const float body_padding_horizontal = 10.0f; - const float body_padding_vertical = 10.0f; - while (current_page == PageType::CHAT && window.isOpen() && !move_room) { sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds(); while (window.pollEvent(event)) { @@ -5626,11 +5631,7 @@ namespace QuickMedia { tab_shade_height = std::floor(tab_vertical_offset) + Tabs::get_height() + room_name_padding_y; - float body_width = window_size.x - body_padding_horizontal * 2.0f; - /*if(body_width <= 480.0f) { - body_width = window_size.x; - body_padding_horizontal = 0.0f; - }*/ + const float body_width = window_size.x; this->body_pos = sf::Vector2f(0.0f, tab_shade_height); if(window_size.x > 900.0f && show_room_side_panel) { @@ -5641,19 +5642,19 @@ namespace QuickMedia { draw_room_list = false; } - body_pos = sf::Vector2f(this->body_pos.x + this->body_size.x + body_padding_horizontal, body_padding_vertical + tab_shade_height); - body_size = sf::Vector2f(body_width - this->body_pos.x - this->body_size.x, window_size.y - chat_input_height_full - body_padding_vertical - tab_shade_height); + body_pos = sf::Vector2f(this->body_pos.x + this->body_size.x, tab_shade_height); + body_size = sf::Vector2f(body_width - this->body_pos.x - this->body_size.x, window_size.y - chat_input_height_full - tab_shade_height); - chat_input_shade.setSize(sf::Vector2f(window_size.x - (body_pos.x - body_padding_horizontal), chat_input_height_full)); - chat_input_shade.setPosition(body_pos.x - body_padding_horizontal, window_size.y - chat_input_shade.getSize().y); + chat_input_shade.setSize(sf::Vector2f(window_size.x - body_pos.x, chat_input_height_full)); + chat_input_shade.setPosition(body_pos.x, window_size.y - chat_input_shade.getSize().y); - chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x + body_pos.x - body_padding_horizontal)); - chat_input.set_position(sf::Vector2f(std::floor(body_pos.x - body_padding_horizontal + logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); + chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x + body_pos.x)); + chat_input.set_position(sf::Vector2f(std::floor(body_pos.x + logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); more_messages_below_rect.setSize(sf::Vector2f(chat_input_shade.getSize().x, gradient_height)); more_messages_below_rect.setPosition(chat_input_shade.getPosition().x, std::floor(window_size.y - chat_input_height_full - gradient_height)); - logo_sprite.setPosition(body_pos.x - body_padding_horizontal + logo_padding_x, std::floor(window_size.y - chat_input_height_full * 0.5f - logo_size.y * 0.5f)); + logo_sprite.setPosition(body_pos.x + logo_padding_x, std::floor(window_size.y - chat_input_height_full * 0.5f - logo_size.y * 0.5f)); } sync_data.messages.clear(); @@ -5746,14 +5747,12 @@ namespace QuickMedia { } else { tabs[selected_tab].body->draw(window, body_pos, body_size); if(selected_tab == MESSAGES_TAB_INDEX && mention.visible && chat_state == ChatState::TYPING_MESSAGE) { - sf::RectangleShape user_mention_background(sf::Vector2f(body_size.x + body_padding_vertical*2.0f, user_mention_body_height)); - user_mention_background.setPosition(sf::Vector2f(body_pos.x - body_padding_vertical, body_pos.y + body_size.y - user_mention_body_height)); + sf::RectangleShape user_mention_background(sf::Vector2f(body_size.x, user_mention_body_height)); + user_mention_background.setPosition(sf::Vector2f(body_pos.x, body_pos.y + body_size.y - user_mention_body_height)); user_mention_background.setFillColor(sf::Color(33, 37, 44)); window.draw(user_mention_background); - tabs[USERS_TAB_INDEX].body->draw(window, - user_mention_background.getPosition() + sf::Vector2f(body_padding_vertical, body_padding_vertical), - user_mention_background.getSize() - sf::Vector2f(body_padding_vertical*2.0f, body_padding_vertical)); + tabs[USERS_TAB_INDEX].body->draw(window, user_mention_background.getPosition(), user_mention_background.getSize()); } } @@ -5787,9 +5786,8 @@ namespace QuickMedia { glScissor(0.0f, 0.0f, this->body_size.x, window_size.y); window.draw(room_list_background); window.draw(room_label); - const float padding_x = std::floor(10.0f * get_ui_scale()); const float tab_y = std::floor(tab_vertical_offset) + room_name_padding_y; - matrix_chat_page->rooms_page->body->draw(window, sf::Vector2f(padding_x, tab_y), sf::Vector2f(this->body_size.x - padding_x * 2.0f, window_size.y - tab_y), Json::Value::nullSingleton()); + matrix_chat_page->rooms_page->body->draw(window, sf::Vector2f(0.0f, tab_y), sf::Vector2f(this->body_size.x, window_size.y - tab_y), Json::Value::nullSingleton()); glDisable(GL_SCISSOR_TEST); } @@ -5851,8 +5849,8 @@ namespace QuickMedia { window.draw(user_mention_background); tabs[USERS_TAB_INDEX].body->draw(window, - sf::Vector2f(body_pos.x, item_background.getPosition().y - user_mention_body_height + body_padding_vertical), - sf::Vector2f(body_size.x, user_mention_body_height - body_padding_vertical)); + sf::Vector2f(body_pos.x, item_background.getPosition().y - user_mention_body_height), + sf::Vector2f(body_size.x, user_mention_body_height)); } replying_to_text.setPosition(body_item_pos.x, body_item_pos.y - replying_to_text_height); @@ -6028,7 +6026,7 @@ namespace QuickMedia { auto rooms_tags_body = create_body(); auto matrix_rooms_tag_page = std::make_unique(this, rooms_tags_body.get()); - auto rooms_body = create_body(); + auto rooms_body = create_body(true); auto rooms_page_search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); auto matrix_rooms_page = std::make_unique(this, rooms_body.get(), "All rooms", nullptr, rooms_page_search_bar.get()); @@ -6453,7 +6451,7 @@ namespace QuickMedia { const float loading_bar_padding_x = std::floor(4.0f * get_ui_scale()); const float loading_bar_padding_y = std::floor(4.0f * get_ui_scale()); RoundedRectangle loading_bar_background(sf::Vector2f(1.0f, 1.0f), std::floor(10.0f * get_ui_scale()), sf::Color(21, 25, 30), &rounded_rectangle_shader); - RoundedRectangle loading_bar(sf::Vector2f(1.0f, 1.0f), std::floor(10.0f * get_ui_scale() - loading_bar_padding_y), sf::Color(0, 85, 119), &rounded_rectangle_shader); + RoundedRectangle loading_bar(sf::Vector2f(1.0f, 1.0f), std::floor(10.0f * get_ui_scale() - loading_bar_padding_y), sf::Color(31, 117, 255), &rounded_rectangle_shader); const float padding_x = std::floor(30.0f * get_ui_scale()); const float spacing_y = std::floor(15.0f * get_ui_scale()); @@ -6634,7 +6632,7 @@ namespace QuickMedia { cancel_button.set_background_color(sf::Color(41, 45, 50)); Button save_button("Save", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale()); - save_button.set_background_color(sf::Color(71, 75, 180)); + save_button.set_background_color(sf::Color(31, 117, 255)); sf::Text file_name_label("File name:", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(16.0f * get_ui_scale())); diff --git a/src/RoundedRectangle.cpp b/src/RoundedRectangle.cpp index 4b06ea8..494a254 100644 --- a/src/RoundedRectangle.cpp +++ b/src/RoundedRectangle.cpp @@ -4,7 +4,9 @@ #include namespace QuickMedia { - 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) { + 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_y(0.0f), band_height(0.0f), band_color(sf::Color::Transparent) + { assert(rounded_rectangle_shader); vertices[0].color = color; vertices[1].color = color; @@ -45,9 +47,21 @@ namespace QuickMedia { return size; } + void RoundedRectangle::set_band(float y, float height) { + band_y = y; + band_height = height; + } + + void RoundedRectangle::set_band_color(sf::Color color) { + band_color = color; + } + void RoundedRectangle::draw(sf::RenderTarget &target) { - rounded_rectangle_shader->setUniform("resolution", size); rounded_rectangle_shader->setUniform("radius", radius); + rounded_rectangle_shader->setUniform("band_y", band_y); + rounded_rectangle_shader->setUniform("band_height", band_height); + 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); target.draw(vertices, 4, sf::Quads, rounded_rectangle_shader); } } \ No newline at end of file diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp index c0a8aad..f7e732a 100644 --- a/src/SearchBar.cpp +++ b/src/SearchBar.cpp @@ -154,7 +154,7 @@ namespace QuickMedia { void SearchBar::onWindowResize(const sf::Vector2f &size) { draw_logo = plugin_logo_sprite.getTexture() != nullptr; - if(size.x * 2.0f < 400.0f) + if(size.x < 400.0f) draw_logo = false; float font_height = text.getCharacterSize() + 7.0f; diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 9dbbe85..8d9bf46 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -43,8 +43,10 @@ namespace QuickMedia { resource_root(resource_root) { display = XOpenDisplay(NULL); - if (!display) - throw std::runtime_error("Failed to open display to X11 server"); + if (!display) { + fprintf(stderr, "Failed to open display to X11 server\n"); + abort(); + } fprintf(stderr, "Video max height: %d\n", monitor_height); } diff --git a/src/plugins/FileManager.cpp b/src/plugins/FileManager.cpp index 42c2f9e..04e284a 100644 --- a/src/plugins/FileManager.cpp +++ b/src/plugins/FileManager.cpp @@ -34,14 +34,12 @@ namespace QuickMedia { return last_write_time; } - PluginResult FileManagerPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - (void)url; - + PluginResult FileManagerPage::submit(const std::string&, const std::string &url, std::vector &result_tabs) { std::filesystem::path new_path; - if(title == "..") + if(url == "..") new_path = current_dir.parent_path(); else - new_path = current_dir / title; + new_path = current_dir / url; if(std::filesystem::is_regular_file(new_path)) { program->select_file(new_path); @@ -89,7 +87,8 @@ namespace QuickMedia { }); if(current_dir != "/") { - auto parent_item = BodyItem::create(".."); + auto parent_item = BodyItem::create("Go to parent directory"); + parent_item->url = ".."; result_items.push_back(std::move(parent_item)); } @@ -114,6 +113,7 @@ namespace QuickMedia { continue; auto body_item = BodyItem::create(p.path().filename().string()); + body_item->url = body_item->get_title(); if(file_mime_type == FILE_MANAGER_MIME_TYPE_IMAGE || file_mime_type == FILE_MANAGER_MIME_TYPE_VIDEO) { body_item->thumbnail_is_local = true; body_item->thumbnail_url = p.path().string(); diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp index 07b5425..d2f81a9 100644 --- a/src/plugins/Fourchan.cpp +++ b/src/plugins/Fourchan.cpp @@ -167,7 +167,7 @@ namespace QuickMedia { } PluginResult FourchanBoardsPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - result_tabs.push_back(Tab{create_body(), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + result_tabs.push_back(Tab{create_body(false), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); return PluginResult::OK; } @@ -353,7 +353,7 @@ namespace QuickMedia { ++body_item_index; } - auto body = create_body(); + auto body = create_body(false); body->items = std::move(result_items); result_tabs.push_back(Tab{std::move(body), std::make_unique(program, board_id, url), nullptr}); return PluginResult::OK; diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index f9cdab5..1e69bd7 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -728,7 +728,7 @@ namespace QuickMedia { } PluginResult MatrixRoomTagsPage::submit(const std::string&, const std::string &url, std::vector &result_tabs) { - auto body = create_body(); + auto body = create_body(true); Body *body_ptr = body.get(); TagData &tag_data = tag_body_items_by_name[url]; body->items = tag_data.room_body_items; @@ -1008,7 +1008,7 @@ namespace QuickMedia { if(strncmp(server_name.c_str(), "www.", 4) == 0) server_name.erase(0, 4); - result_tabs.push_back(Tab{create_body(), std::make_unique(program, matrix, server_name), create_search_bar("Search...", 350)}); + result_tabs.push_back(Tab{create_body(), std::make_unique(program, matrix, server_name), create_search_bar("Search...", 400)}); return PluginResult::OK; } @@ -2174,6 +2174,11 @@ namespace QuickMedia { message->related_event_type = RelatedEventType::REDACTION; message->transaction_id = std::move(transaction_id); + if(sent_by_somebody_else) { + std::string sender_display_name = extract_first_line_remove_newline_elipses(room_data->get_user_display_name(user_sender), AUTHOR_MAX_LENGTH); + message->body += " by " + sender_display_name; + } + const rapidjson::Value &reason_json = GetMember(*content_json, "reason"); if(reason_json.IsString()) { message->body += ", reason: "; @@ -3871,7 +3876,7 @@ namespace QuickMedia { }; std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/join/" + room_id, server_response, std::move(additional_args), true); + DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/join/" + url_param_encode(room_id), server_response, std::move(additional_args), true); if(download_result == DownloadResult::OK) { std::lock_guard invite_lock(invite_mutex); auto invite_it = invites.find(room_id); @@ -3909,7 +3914,7 @@ namespace QuickMedia { }; std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room_id + "/leave", server_response, std::move(additional_args), true); + DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + url_param_encode(room_id) + "/leave", server_response, std::move(additional_args), true); if(download_result == DownloadResult::OK) { RoomData *room = get_room_by_id(room_id); if(room) { @@ -3991,6 +3996,7 @@ namespace QuickMedia { if(!description.empty()) description += '\n'; description += canonical_alias_json.GetString(); + room_body_item->url = canonical_alias_json.GetString(); } const rapidjson::Value &num_joined_members_json = GetMember(chunk_item_json, "num_joined_members"); diff --git a/src/plugins/Page.cpp b/src/plugins/Page.cpp index 21a33cb..9eb874f 100644 --- a/src/plugins/Page.cpp +++ b/src/plugins/Page.cpp @@ -29,8 +29,8 @@ namespace QuickMedia { return DownloadResult::OK; } - std::unique_ptr Page::create_body() { - return program->create_body(); + std::unique_ptr Page::create_body(bool plain_text_list) { + return program->create_body(plain_text_list); } std::unique_ptr Page::create_search_bar(const std::string &placeholder_text, int search_delay) { diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index d164bc5..f7b36d6 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -190,7 +190,9 @@ namespace QuickMedia { if(!desc.empty()) desc += '\n'; desc += '\n'; - desc += description_snippet.value(); + std::string description_snippet_stripped = strip(description_snippet.value()); + string_replace_all(description_snippet_stripped, "\n\n", "\n"); + desc += std::move(description_snippet_stripped); } body_item->set_description(std::move(desc)); body_item->set_description_color(sf::Color(179, 179, 179)); @@ -247,7 +249,9 @@ namespace QuickMedia { if(!desc.empty()) desc += '\n'; desc += '\n'; - desc += description.value(); + std::string description_snippet_stripped = strip(description.value()); + string_replace_all(description_snippet_stripped, "\n\n", "\n"); + desc += std::move(description_snippet_stripped); } body_item->set_description(std::move(desc)); body_item->set_description_color(sf::Color(179, 179, 179)); -- cgit v1.2.3