From 4aec31515ff6f61f41dfd66551a3fce44f243535 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 20 Mar 2021 07:06:06 +0100 Subject: More work on touch (behind QM_ENABLE_TOUCH=1 environment variable), save thumbnails with their size so using a different scaling will update thumbnails to the same scale --- src/AsyncImageLoader.cpp | 2 + src/Body.cpp | 137 ++++++++++++++++++++++++++++++----------------- src/QuickMedia.cpp | 43 +++++++++++---- src/plugins/Matrix.cpp | 15 ++++-- 4 files changed, 134 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/AsyncImageLoader.cpp b/src/AsyncImageLoader.cpp index d0a67c4..9792781 100644 --- a/src/AsyncImageLoader.cpp +++ b/src/AsyncImageLoader.cpp @@ -164,6 +164,8 @@ namespace QuickMedia { SHA256 sha256; sha256.add(url.data(), url.size()); Path thumbnail_path = get_cache_dir().join("thumbnails").join(sha256.getHash()); + if(resize_target_size.x != 0 && resize_target_size.y != 0) + thumbnail_path.append("_" + std::to_string(resize_target_size.x) + "x" + std::to_string(resize_target_size.y)); if(get_file_type(thumbnail_path) == FileType::REGULAR) { thumbnail_data->loading_state = LoadingState::LOADING; image_load_queue.push({ url, thumbnail_path, local, thumbnail_data, resize_target_size }); diff --git a/src/Body.cpp b/src/Body.cpp index 293f516..667232e 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -136,6 +136,10 @@ namespace QuickMedia { item_background.setFillColor(sf::Color(55, 60, 68)); sf::Vector2f loading_icon_size(loading_icon.getTexture()->getSize().x, loading_icon.getTexture()->getSize().y); loading_icon.setOrigin(loading_icon_size.x * 0.5f, loading_icon_size.y * 0.5f); + const char *qm_enable_touch = getenv("QM_ENABLE_TOUCH"); + if(qm_enable_touch && qm_enable_touch[0] == '1') { + experimental_use_touch = true; + } } // TODO: Make this work with wraparound enabled? @@ -372,35 +376,48 @@ namespace QuickMedia { } bool Body::on_event(const sf::RenderWindow &window, const sf::Event &event) { - #if 0 + if(!experimental_use_touch) + return false; + if(!mouse_state_set) { mouse_state_set = true; mouse_left_pressed = sf::Mouse::isButtonPressed(sf::Mouse::Left); - if(mouse_left_pressed) { - mouse_pos_raw = sf::Mouse::getPosition(window); - mouse_pos = sf::Vector2f(mouse_pos_raw.x, mouse_pos_raw.y); - prev_mouse_pos = mouse_pos; - return true; + if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) { + auto mpos = sf::Mouse::getPosition(window); + if(sf::FloatRect(body_pos, body_size).contains(sf::Vector2f(mpos.x, mpos.y))) { + mouse_left_pressed = true; + mouse_pos_raw = sf::Mouse::getPosition(window); + mouse_pos = sf::Vector2f(mouse_pos_raw.x, mouse_pos_raw.y); + prev_mouse_pos = mouse_pos; + mouse_click_pos = mouse_pos; + mouse_press_pixels_moved_abs = 0.0; + return true; + } } } - if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left && !mouse_left_pressed) { + if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left && !mouse_left_pressed && sf::FloatRect(body_pos, body_size).contains(sf::Vector2f(event.mouseButton.x, event.mouseButton.y))) { mouse_left_pressed = true; mouse_pos_raw.x = event.mouseButton.x; mouse_pos_raw.y = event.mouseButton.y; mouse_pos = sf::Vector2f(mouse_pos_raw.x, mouse_pos_raw.y); prev_mouse_pos = mouse_pos; + mouse_click_pos = mouse_pos; + mouse_press_pixels_moved_abs = 0.0; return true; } else if(event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left && mouse_left_pressed) { mouse_left_pressed = false; + mouse_left_clicked = true; + mouse_release_pos = sf::Vector2f(event.mouseButton.x, event.mouseButton.y); return true; } else if(event.type == sf::Event::MouseMoved && mouse_left_pressed) { + sf::Vector2i mouse_pos_diff(event.mouseMove.x - mouse_pos_raw.x, event.mouseMove.y - mouse_pos_raw.y); + mouse_press_pixels_moved_abs += std::sqrt(mouse_pos_diff.x*mouse_pos_diff.x + mouse_pos_diff.y*mouse_pos_diff.y); mouse_pos_raw.x = event.mouseMove.x; mouse_pos_raw.y = event.mouseMove.y; return true; } - #endif return false; } @@ -415,51 +432,60 @@ namespace QuickMedia { sf::Vector2f scissor_size = size; const float start_y = pos.y; + body_pos = pos; + body_size = size; + elapsed_time_sec = draw_timer.getElapsedTime().asSeconds(); -#if 0 - float frame_time = frame_timer.restart().asSeconds(); - if(frame_time > 2.0f) - frame_time = 2.0f; - - const sf::Vector2f mouse_pos_diff(mouse_pos_raw.x - mouse_pos.x, mouse_pos_raw.y - mouse_pos.y); - const float move_speed = 25.0f; - mouse_pos.x += (mouse_pos_diff.x * frame_time * move_speed); - mouse_pos.y += (mouse_pos_diff.y * frame_time * move_speed); - - sf::Vector2f mouse_smooth_diff(mouse_pos.x - prev_mouse_pos.x, mouse_pos.y - prev_mouse_pos.y); - prev_mouse_pos = mouse_pos; - - if(mouse_left_pressed) { - selected_scrolled += mouse_smooth_diff.y; - page_scroll += mouse_smooth_diff.y; - mouse_scroll_accel = mouse_smooth_diff; - } else { - selected_scrolled += mouse_scroll_accel.y; - page_scroll += mouse_scroll_accel.y; - const float scroll_deaccel = 1.02f; - double deaccel = scroll_deaccel * (1.0 + frame_time); - if(deaccel < 0.0001) - deaccel = 1.0; - - mouse_scroll_accel.x /= deaccel; - if(fabs(mouse_scroll_accel.x) < 0.0001) - mouse_scroll_accel.x = 0.0; - - mouse_scroll_accel.y /= deaccel; - if(fabs(mouse_scroll_accel.y) < 0.0001) - mouse_scroll_accel.y = 0.0; - } - if(selected_item != -1) { - if(selected_scrolled <= -selected_item_height) { - selected_scrolled += selected_item_height; - select_next_item(false); - } else if(selected_scrolled >= selected_item_height) { - selected_scrolled -= selected_item_height; - select_previous_item(false); + if(experimental_use_touch) { + float frame_time = frame_timer.restart().asSeconds(); + if(frame_time > 2.0f) + frame_time = 2.0f; + + const sf::Vector2f mouse_pos_diff(mouse_pos_raw.x - mouse_pos.x, mouse_pos_raw.y - mouse_pos.y); + const float move_speed = 25.0f; + mouse_pos.x += (mouse_pos_diff.x * frame_time * move_speed); + mouse_pos.y += (mouse_pos_diff.y * frame_time * move_speed); + + sf::Vector2f mouse_smooth_diff(mouse_pos.x - prev_mouse_pos.x, mouse_pos.y - prev_mouse_pos.y); + prev_mouse_pos = mouse_pos; + + if(items_cut_off) { + if(mouse_left_pressed) { + selected_scrolled += mouse_smooth_diff.y; + page_scroll += mouse_smooth_diff.y; + mouse_scroll_accel = mouse_smooth_diff; + } else { + selected_scrolled += mouse_scroll_accel.y; + page_scroll += mouse_scroll_accel.y; + } + } + + if(!mouse_left_pressed) { + const float scroll_deaccel = 1.02f; + double deaccel = scroll_deaccel * (1.0 + frame_time); + if(deaccel < 0.0001) + deaccel = 1.0; + + mouse_scroll_accel.x /= deaccel; + if(fabs(mouse_scroll_accel.x) < 0.0001) + mouse_scroll_accel.x = 0.0; + + mouse_scroll_accel.y /= deaccel; + if(fabs(mouse_scroll_accel.y) < 0.0001) + mouse_scroll_accel.y = 0.0; + } + + if(selected_item != -1) { + if(selected_scrolled <= -selected_item_height) { + selected_scrolled += selected_item_height; + select_next_item(false); + } else if(selected_scrolled >= selected_item_height) { + selected_scrolled -= selected_item_height; + select_previous_item(false); + } } } -#endif //item_background.setFillColor(front_color); //item_background.setOutlineThickness(1.0f); @@ -483,6 +509,7 @@ namespace QuickMedia { items_cut_off = false; offset_to_top = 0.0f; offset_to_bottom = 0.0f; + mouse_left_clicked = false; return; } @@ -559,6 +586,7 @@ namespace QuickMedia { page_scroll = 0.0f; } + page_scroll = std::floor(page_scroll); pos.y += page_scroll; bool last_item_fully_visible_set = false; @@ -650,6 +678,8 @@ namespace QuickMedia { if(!items_cut_off_set) items_cut_off = false; + mouse_left_clicked = false; + for(auto it = item_thumbnail_textures.begin(); it != item_thumbnail_textures.end();) { if(!it->second->referenced) it = item_thumbnail_textures.erase(it); @@ -813,6 +843,15 @@ namespace QuickMedia { item_pos.x = std::floor(pos.x); item_pos.y = std::floor(pos.y); + if(body_item_select_callback && mouse_left_clicked) { + sf::FloatRect item_box(pos, sf::Vector2f(size.x, item_height)); + // TODO: Scale mouse_press_pixels_moved_abs with monitor PPI instead of using get_ui_scale() + if(item_box.contains(mouse_click_pos) && item_box.contains(mouse_release_pos) && mouse_press_pixels_moved_abs <= 50.0 * get_ui_scale()) { + set_selected_item(item_index, false); + body_item_select_callback(item); + } + } + item_separator.setSize(sf::Vector2f(std::max(0.0f, size.x - 20.0f), 1.0f)); item_separator.setPosition(item_pos + sf::Vector2f(10.0f, std::floor(item_height + spacing_y * 0.5f))); window.draw(item_separator); diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index d54229f..61b2d1b 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -53,6 +53,7 @@ static const sf::Color tab_selected_color(55, 60, 68); static const float tab_margin_x = std::floor(10.0f * QuickMedia::get_ui_scale()); static int FPS_IDLE = 2; static const double IDLE_TIMEOUT_SEC = 2.0; +static const sf::Vector2i AVATAR_THUMBNAIL_SIZE(std::floor(32 * QuickMedia::get_ui_scale()), std::floor(32 * QuickMedia::get_ui_scale())); // Prevent writing to broken pipe from exiting the program static void sigpipe_handler(int) { @@ -1100,7 +1101,9 @@ namespace QuickMedia { window_size.x = window_size_u.x; window_size.y = window_size_u.y; - auto submit_handler = [this, &after_submit_handler, &json_chapters, &tabs, &tab_associated_data, &selected_tab, &loop_running, &redraw]() { + std::function submit_handler; + + submit_handler = [this, &submit_handler, &after_submit_handler, &json_chapters, &tabs, &tab_associated_data, &selected_tab, &loop_running, &redraw]() { BodyItem *selected_item = tabs[selected_tab].body->get_selected(); if(!selected_item) return; @@ -1195,6 +1198,9 @@ namespace QuickMedia { break; current_chat_room = matrix->get_room_by_id(selected_item->url); } + tabs[selected_tab].body->body_item_select_callback = [&submit_handler](BodyItem *body_item) { + submit_handler(); + }; //select_body_item_by_room(tabs[selected_tab].body.get(), current_chat_room); current_chat_room = nullptr; } else { @@ -1213,6 +1219,10 @@ namespace QuickMedia { for(size_t i = 0; i < tabs.size(); ++i) { Tab &tab = tabs[i]; + tab.body->body_item_select_callback = [&submit_handler](BodyItem *body_item) { + submit_handler(); + }; + TabAssociatedData &associated_data = tab_associated_data[i]; if(!tab.search_bar) continue; @@ -1263,6 +1273,7 @@ namespace QuickMedia { window_size.y = event.size.height; sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); window.setView(sf::View(visible_area)); + idle_active_handler(); } if(tabs[selected_tab].search_bar) { @@ -2767,6 +2778,7 @@ namespace QuickMedia { window_size.y = event.size.height; sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); window.setView(sf::View(visible_area)); + idle_active_handler(); } if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) @@ -3122,6 +3134,7 @@ namespace QuickMedia { sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); window.setView(sf::View(visible_area)); redraw = true; + idle_active_handler(); } else if(event.type == sf::Event::GainedFocus) { redraw = true; } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Tab) { @@ -3178,7 +3191,7 @@ namespace QuickMedia { body_item->thumbnail_url = room->get_user_avatar_url(message->user); body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that - body_item->thumbnail_size = sf::Vector2i(32, 32); + body_item->thumbnail_size = AVATAR_THUMBNAIL_SIZE; } // TODO: Show image thumbnail inline instead of url to image and showing it as the thumbnail of the body item body_item->url = message->url; @@ -3345,7 +3358,7 @@ namespace QuickMedia { } body_item->set_description("Message deleted"); body_item->set_description_color(sf::Color::White); - body_item->thumbnail_size = sf::Vector2i(32, 32); + body_item->thumbnail_size = AVATAR_THUMBNAIL_SIZE; body_item->url.clear(); }; @@ -4170,7 +4183,7 @@ namespace QuickMedia { pinned_body_item->thumbnail_url = user_avatar_url; pinned_body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that - pinned_body_item->thumbnail_size = sf::Vector2i(32, 32); + pinned_body_item->thumbnail_size = AVATAR_THUMBNAIL_SIZE; } } }; @@ -4190,7 +4203,7 @@ namespace QuickMedia { message_body_items->thumbnail_url = user_avatar_url; message_body_items->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that - message_body_items->thumbnail_size = sf::Vector2i(32, 32); + message_body_items->thumbnail_size = AVATAR_THUMBNAIL_SIZE; } } }; @@ -4209,7 +4222,7 @@ namespace QuickMedia { pinned_body_item->thumbnail_url = current_room->get_user_avatar_url(message->user); pinned_body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that - pinned_body_item->thumbnail_size = sf::Vector2i(32, 32); + pinned_body_item->thumbnail_size = AVATAR_THUMBNAIL_SIZE; } } }; @@ -4227,7 +4240,7 @@ namespace QuickMedia { message_body_items->thumbnail_url = current_room->get_user_avatar_url(message->user); message_body_items->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that - message_body_items->thumbnail_size = sf::Vector2i(32, 32); + message_body_items->thumbnail_size = AVATAR_THUMBNAIL_SIZE; } } }; @@ -4280,9 +4293,13 @@ namespace QuickMedia { float tab_shade_height = 0.0f; bool frame_skip_text_entry = false; + room_tabs[room_selected_tab].body->body_item_select_callback = [&move_room](BodyItem *body_item) { + move_room = true; + }; + SyncData sync_data; - while (current_page == PageType::CHAT && window.isOpen()) { + while (current_page == PageType::CHAT && window.isOpen() && !move_room) { sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds(); while (window.pollEvent(event)) { if(chat_state == ChatState::URL_SELECTION) { @@ -4296,6 +4313,9 @@ namespace QuickMedia { base_event_handler(event, PageType::EXIT, tabs[selected_tab].body.get(), nullptr, false, false); event_idle_handler(event); + if(draw_room_list) + room_tabs[room_selected_tab].body->on_event(window, event); + if(event.type == sf::Event::KeyPressed && event.key.control && event.key.alt && (chat_state == ChatState::NAVIGATING || chat_state == ChatState::URL_SELECTION)) { if(event.key.code == sf::Keyboard::Up || (event.key.control && event.key.code == sf::Keyboard::K)) { room_tabs[room_selected_tab].body->select_previous_item(); @@ -4336,7 +4356,10 @@ namespace QuickMedia { redraw = true; } else if(event.type == sf::Event::LostFocus) { is_window_focused = false; - } else if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) { + } else if(event.type == sf::Event::Resized) { + redraw = true; + idle_active_handler(); + } else if(event.type == sf::Event::GainedFocus) { redraw = true; } else if(event.type == sf::Event::KeyPressed && chat_state == ChatState::NAVIGATING) { if(event.key.code == sf::Keyboard::Up || event.key.code == sf::Keyboard::PageUp || event.key.code == sf::Keyboard::Home || (event.key.control && event.key.code == sf::Keyboard::K)) { @@ -4631,7 +4654,7 @@ namespace QuickMedia { } if(current_room && current_room->body_item && room_avatar_thumbnail_data->loading_state == LoadingState::NOT_LOADED) - AsyncImageLoader::get_instance().load_thumbnail(current_room->body_item->thumbnail_url, false, sf::Vector2i(32, 32), use_tor, room_avatar_thumbnail_data); + AsyncImageLoader::get_instance().load_thumbnail(current_room->body_item->thumbnail_url, false, AVATAR_THUMBNAIL_SIZE, use_tor, room_avatar_thumbnail_data); if(room_avatar_thumbnail_data->loading_state == LoadingState::FINISHED_LOADING && room_avatar_thumbnail_data->image->getSize().x > 0 && room_avatar_thumbnail_data->image->getSize().y > 0) { if(!room_avatar_thumbnail_data->texture.loadFromImage(*room_avatar_thumbnail_data->image)) diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index aa6de40..263a948 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -6,11 +6,13 @@ #include "../../include/Program.hpp" #include "../../include/base64_url.hpp" #include "../../include/Json.hpp" +#include "../../include/Utils.hpp" #include #include #include #include #include +#include #include #include #include "../../include/QuickMedia.hpp" @@ -1602,6 +1604,11 @@ namespace QuickMedia { return media_url.substr(start, end - start); } + static std::string get_thumbnail_url(const std::string &homeserver, const std::string &mxc_id) { + std::string size = std::to_string(int(32 * get_ui_scale())); + return homeserver + "/_matrix/media/r0/thumbnail/" + mxc_id + "?width=" + size + "&height=" + size + "&method=crop"; + } + std::shared_ptr Matrix::parse_user_info(const rapidjson::Value &json, const std::string &user_id, RoomData *room_data) { assert(json.IsObject()); std::string avatar_url_str; @@ -1614,7 +1621,7 @@ namespace QuickMedia { std::string display_name = display_name_json.IsString() ? display_name_json.GetString() : user_id; std::string avatar_url = thumbnail_url_extract_media_id(avatar_url_str); if(!avatar_url.empty()) - avatar_url = homeserver + "/_matrix/media/r0/thumbnail/" + avatar_url + "?width=32&height=32&method=crop"; // TODO: Remove the constant strings around to reduce memory usage (6.3mb) + avatar_url = get_thumbnail_url(homeserver, avatar_url); // TODO: Remove the constant strings around to reduce memory usage (6.3mb) //auto user_info = std::make_shared(room_data, user_id, std::move(display_name), std::move(avatar_url)); // Overwrites user data //room_data->add_user(user_info); @@ -1983,7 +1990,7 @@ namespace QuickMedia { body = user_display_name + " changed their profile picture"; std::string new_avatar_url_str = thumbnail_url_extract_media_id(new_avatar_url_json.GetString()); if(!new_avatar_url_str.empty()) - new_avatar_url_str = homeserver + "/_matrix/media/r0/thumbnail/" + new_avatar_url_str + "?width=32&height=32&method=crop"; // TODO: Remove the constant strings around to reduce memory usage (6.3mb) + new_avatar_url_str = get_thumbnail_url(homeserver, new_avatar_url_str); // TODO: Remove the constant strings around to reduce memory usage (6.3mb) room_data->set_user_avatar_url(user, std::move(new_avatar_url_str)); } else if((!new_avatar_url_json.IsString() || new_avatar_url_json.GetStringLength() == 0) && prev_avatar_url_json.IsString()) { body = user_display_name + " removed their profile picture"; @@ -2200,7 +2207,7 @@ namespace QuickMedia { continue; std::string url_json_str = url_json.GetString() + 6; - room_data->set_avatar_url(homeserver + "/_matrix/media/r0/thumbnail/" + thumbnail_url_extract_media_id(url_json_str) + "?width=32&height=32&method=crop"); + room_data->set_avatar_url(get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(url_json_str))); room_data->avatar_is_fallback = false; } } @@ -3742,7 +3749,7 @@ namespace QuickMedia { if(avatar_url_json.IsString()) avatar_url = std::string(avatar_url_json.GetString(), avatar_url_json.GetStringLength()); if(!avatar_url.empty()) - avatar_url = homeserver + "/_matrix/media/r0/thumbnail/" + thumbnail_url_extract_media_id(avatar_url) + "?width=32&height=32&method=crop"; // TODO: Remove the constant strings around to reduce memory usage (6.3mb) + avatar_url = get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(avatar_url)); // TODO: Remove the constant strings around to reduce memory usage (6.3mb) room->set_user_avatar_url(user, std::move(avatar_url)); room->set_user_display_name(user, std::move(display_name)); } -- cgit v1.2.3