From 28168bb3a63b7506a79441d6ce5ed312ba6f6e1a Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 17 May 2021 04:09:47 +0200 Subject: Make body movement smooth, async load video related videos to allow cancellation with esc --- src/Body.cpp | 113 ++++++++++++++++++++++++++++++++++++++----------- src/QuickMedia.cpp | 21 ++++++--- src/main.cpp | 1 + src/plugins/Matrix.cpp | 4 ++ 4 files changed, 109 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index ffafb90..d7a4456 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -284,6 +284,8 @@ namespace QuickMedia { page_scroll = 0.0f; clamp_selection(); clamp_selected_item_to_body_count = 1; + //item_background_target_pos_y = body_pos.y; + //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); } void Body::select_last_item() { @@ -294,6 +296,8 @@ namespace QuickMedia { //page_scroll = 0.0f; clamp_selection(); clamp_selected_item_to_body_count = 1; + //item_background_target_pos_y = body_pos.y + body_size.y - item_background.get_size().y; + //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); } void Body::clear_items() { @@ -304,6 +308,8 @@ namespace QuickMedia { prev_selected_item = selected_item; page_scroll = 0.0f; clamp_selected_item_to_body_count = 1; + //item_background_target_pos_y = body_pos.y; + //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); } void Body::prepend_items(BodyItems new_items) { @@ -481,6 +487,9 @@ namespace QuickMedia { sf::Vector2f scissor_pos = pos; sf::Vector2f scissor_size = size; const float start_y = pos.y; + float frame_time = frame_timer.restart().asSeconds(); + if(frame_time > 2.0f) + frame_time = 2.0f; body_pos = pos; bool body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f; @@ -489,26 +498,33 @@ namespace QuickMedia { elapsed_time_sec = draw_timer.getElapsedTime().asSeconds(); + const bool scroll_past_first = first_item_fully_visible && offset_to_top > 0.1f; + const bool scroll_past_last = last_item_fully_visible && offset_to_bottom > 0.1f; + + if((attach_side == AttachSide::BOTTOM && scroll_past_first) || (attach_side == AttachSide::TOP && scroll_past_last)) + body_size_changed = true; + bool keep_selected_inside_body = clamp_selected_item_to_body_count > 0 || offset_to_top > 0.1f || offset_to_bottom > 0.1f; - if(has_scrolled_with_input) { - clamp_selected_item_to_body_count--; - if(clamp_selected_item_to_body_count < 0) - clamp_selected_item_to_body_count = 0; - } + clamp_selected_item_to_body_count--; + if(clamp_selected_item_to_body_count < 0) + clamp_selected_item_to_body_count = 0; if(is_touch_enabled()) { - 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); + mouse_pos.x += (mouse_pos_diff.x * std::min(1.0f, frame_time * move_speed)); + mouse_pos.y += (mouse_pos_diff.y * std::min(1.0f, 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 && (scroll_past_first || scroll_past_last)) { + mouse_scroll_accel.x = 0.0f; + mouse_scroll_accel.y = 0.0f; + mouse_pos.x = mouse_pos_raw.x; + mouse_pos.y = mouse_pos_raw.y; + } + if(items_cut_off) { if(mouse_left_pressed) { selected_scrolled += mouse_smooth_diff.y; @@ -531,14 +547,14 @@ namespace QuickMedia { clamp_selection(); // TODO: Cache this if(on_top_reached) { - int first_visible_item = -1; + int first_visible_item_n = -1; for(int i = 0; i <= selected_item; ++i) { if(items[i]->visible) { - first_visible_item = i; + first_visible_item_n = i; break; } } - if(first_visible_item == first_fully_visible_item) + if(first_visible_item_n == first_fully_visible_item) on_top_reached(); } } else if(mouse_scroll_accel.y < -0.1 && last_fully_visible_item != -1) { @@ -546,14 +562,14 @@ namespace QuickMedia { clamp_selection(); // TODO: Cache this if(on_bottom_reached) { - int last_visible_item = -1; + int last_visible_item_n = -1; for(int i = items.size() - 1; i >= selected_item; --i) { if(items[i]->visible) { - last_visible_item = i; + last_visible_item_n = i; break; } } - if(last_visible_item == last_fully_visible_item) + if(last_visible_item_n == last_fully_visible_item) on_bottom_reached(); } } @@ -574,10 +590,28 @@ namespace QuickMedia { } } - item_separator.setFillColor(line_separator_color); + const double scroll_diff = extra_scroll_target - extra_scroll_current; + const double scroll_move_speed = 25.0; + extra_scroll_current += (scroll_diff * std::min(1.0, frame_time * scroll_move_speed)); + + double scroll_smooth_diff = extra_scroll_current - prev_extra_scroll; + prev_extra_scroll = extra_scroll_current; + + selected_scrolled += scroll_smooth_diff; + + bool selected_item_fits_on_screen = selected_item_height <= size.y; + if(selected_item_fits_on_screen && render_selected_item_bg && !first_item_fully_visible && !last_item_fully_visible && items_cut_off && (selected_item == first_visible_item || selected_item == last_visible_item || selected_item == first_fully_visible_item || selected_item == last_fully_visible_item)) { + page_scroll += scroll_smooth_diff; + keep_selected_inside_body = false; + } + + //item_separator.setFillColor(line_separator_color); + const int prev_num_visible_items = num_visible_items; num_visible_items = 0; first_fully_visible_item = -1; last_fully_visible_item = -1; + first_visible_item = -1; + last_visible_item = -1; selected_line_top_visible = true; selected_line_bottom_visible = true; @@ -594,7 +628,8 @@ namespace QuickMedia { offset_to_top = 0.0f; offset_to_bottom = 0.0f; mouse_left_clicked = false; - last_visible_item = -1; + //item_background_target_pos_y = body_pos.y; + //item_background.set_position(sf::Vector2f(body_pos.x, item_background_target_pos_y)); return; } @@ -615,6 +650,7 @@ namespace QuickMedia { int i = prev_selected_item; const int prev_body_item_index = get_previous_visible_item(i); BodyItem *prev_body_item = prev_body_item_index == -1 ? nullptr : items[prev_body_item_index].get(); + double scroll_before = page_scroll; while(num_items_scrolled < selected_int_diff_abs && i < num_items) { if(items[i]->visible) { const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, items[i].get()); @@ -628,10 +664,13 @@ namespace QuickMedia { ++i; } prev_selected_item = selected_item; + if(selected_item_fits_on_screen) + extra_scroll_target -= (page_scroll - scroll_before); } else if(selected_item_diff < 0) { int num_items_scrolled = 0; int i = prev_selected_item - 1; BodyItem *prev_body_item; + double scroll_before = page_scroll; while(num_items_scrolled < selected_int_diff_abs && i >= 0) { if(items[i]->visible) { const int prev_body_item_index = get_previous_visible_item(i); @@ -646,6 +685,8 @@ namespace QuickMedia { --i; } prev_selected_item = selected_item; + if(selected_item_fits_on_screen) + extra_scroll_target -= (page_scroll - scroll_before); } bool merge_with_previous = false; @@ -669,7 +710,8 @@ namespace QuickMedia { } else if(attach_side == AttachSide::BOTTOM) { if(last_item_fully_visible) { page_scroll += offset_to_bottom; - } else { + } else if(first_item_fully_visible && !last_item_fully_visible && body_size_changed) { + page_scroll -= offset_to_top; //page_scroll = get_offset_to_last_visible_item(size); } } @@ -678,7 +720,7 @@ namespace QuickMedia { selected_item_height = get_item_height(items[selected_item].get(), size.x, true, true, merge_with_previous, selected_item); selected_item_height += spacing_y; - bool selected_item_fits_on_screen = selected_item_height <= size.y; + selected_item_fits_on_screen = selected_item_height <= size.y; selected_line_top_visible = pos.y - start_y + page_scroll >= 0.0f; selected_line_bottom_visible = pos.y - start_y + page_scroll + selected_item_height <= size.y; @@ -719,6 +761,25 @@ namespace QuickMedia { sf::Vector2u window_size = window.getSize(); + if(prev_num_visible_items > 0) { + 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 = 50.0f; + item_background.set_position(sf::Vector2f(pos.x, item_background_prev_pos_y + (item_background_pos_diff * std::min(1.0f, frame_time * item_background_move_speed)))); + + 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 = 50.0f; + item_background.set_size(sf::Vector2f(size.x, item_background_prev_height + (item_background_height_diff * std::min(1.0f, frame_time * item_background_height_speed)))); + + if(render_selected_item_bg) { + glEnable(GL_SCISSOR_TEST); + glScissor(scissor_pos.x, (int)window_size.y - (int)scissor_pos.y - (int)scissor_size.y, scissor_size.x, scissor_size.y); + item_background.draw(window); + glDisable(GL_SCISSOR_TEST); + } + } + sf::Vector2f prev_pos = pos; int i; for(i = selected_item - 1; i >= 0;) { @@ -753,6 +814,7 @@ namespace QuickMedia { draw_item(window, item.get(), prev_pos, size, item_height, i, content_progress, true, merge_with_previous); glDisable(GL_SCISSOR_TEST); ++num_visible_items; + first_visible_item = i; last_visible_item = i; if(first_item_fully_visible) @@ -810,6 +872,8 @@ namespace QuickMedia { after_pos.y += item_height; after_pos.y += spacing_y; ++num_visible_items; + if(first_visible_item == -1) + first_visible_item = i; last_visible_item = i; int next_body_item_index = get_next_visible_item(i); @@ -1125,10 +1189,9 @@ namespace QuickMedia { //item_separator.setPosition(item_pos + sf::Vector2f(10.0f, std::floor(item_height + spacing_y * 0.5f))); //window.draw(item_separator); - if(render_selected_item_bg && item_index == selected_item) { - item_background.set_position(item_pos); - item_background.set_size(sf::Vector2f(size.x, item_height)); - item_background.draw(window); + if(item_index == selected_item) { + item_background_target_pos_y = item_pos.y; + item_background_target_height = item_height; } float text_offset_x = padding_x; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index cd4a279..cd1377a 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -561,7 +561,6 @@ namespace QuickMedia { } void Program::init(Window parent_window, std::string &program_path) { - XInitThreads(); disp = XOpenDisplay(NULL); if (!disp) throw std::runtime_error("Failed to open display to X11 server"); @@ -2187,8 +2186,15 @@ namespace QuickMedia { return; channel_url.clear(); - // TODO: Remove this and use lazy_fetch instead - related_videos = video_page->get_related_media(video_url, channel_url); + TaskResult load_related_media_result = run_task_with_loading_screen([video_page, &related_videos, &video_url, &channel_url]{ + related_videos = video_page->get_related_media(video_url, channel_url); + return true; + }); + + if(load_related_media_result == TaskResult::CANCEL) { + current_page = previous_page; + return; + } // TODO: Make this also work for other video plugins if(strcmp(plugin_name, "youtube") != 0 || resume_video) @@ -2297,7 +2303,7 @@ namespace QuickMedia { KeySym pressed_keysym = XKeycodeToKeysym(disp, xev.xkey.keycode, 0); #pragma GCC diagnostic pop bool pressing_ctrl = (CLEANMASK(xev.xkey.state) == ControlMask); - if(pressed_keysym == XK_Escape || pressed_keysym == XK_BackSpace || pressed_keysym == XK_q) { + if(pressed_keysym == XK_Escape || pressed_keysym == XK_q || pressed_keysym == XK_BackSpace) { current_page = previous_page; break; } else if(pressed_keysym == XK_f && pressing_ctrl) { @@ -2402,7 +2408,7 @@ namespace QuickMedia { if(new_video_url.empty() && parent_page && parent_body_page) { BodyItems new_body_items; const int fetch_page = (*parent_body_page) + 1; - run_task_with_loading_screen([parent_page, parent_page_search, fetch_page, &new_body_items] { + TaskResult load_next_page_result = run_task_with_loading_screen([parent_page, parent_page_search, fetch_page, &new_body_items] { if(parent_page->get_page(parent_page_search, fetch_page, new_body_items) != PluginResult::OK) { fprintf(stderr, "Failed to get next page (page %d)\n", fetch_page); return false; @@ -2418,6 +2424,11 @@ namespace QuickMedia { related_videos = std::move(new_body_items); find_next_video(); } + + if(load_next_page_result == TaskResult::CANCEL) { + current_page = previous_page; + continue; + } } // If there are no videos to play, then dont play any... diff --git a/src/main.cpp b/src/main.cpp index 89d824d..15041d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include int main(int argc, char **argv) { + XInitThreads(); setlocale(LC_ALL, "C"); // Sigh... stupid C QuickMedia::Program program; return program.run(argc, argv); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 8679a54..1d471fc 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -920,12 +920,16 @@ namespace QuickMedia { PluginResult MatrixInviteDetailsPage::submit(const std::string &title, const std::string&, std::vector&) { if(title == "Accept") { if(matrix->join_room(room_id) == PluginResult::OK) { + // TODO: Wait for room invite list change from the server instead of removing room here. + // Then the invite list can be updated when accepting/declining an invite in another client. invites_page->remove_body_item_by_room_id(room_id); } else { show_notification("QuickMedia", "Failed to accept the room invite", Urgency::CRITICAL); } } else if(title == "Decline") { if(matrix->leave_room(room_id) == PluginResult::OK) { + // TODO: Wait for room invite list change from the server instead of removing room here. + // Then the invite list can be updated when accepting/declining an invite in another client. invites_page->remove_body_item_by_room_id(room_id); } else { show_notification("QuickMedia", "Failed to decline the room invite", Urgency::CRITICAL); -- cgit v1.2.3