From c3819073118488ffef5482957758d65be8c33cec Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 13 Mar 2022 05:19:37 +0100 Subject: Attempt to fix video player focus, add keys to navigate to previous/next chapter in image scroll view --- README.md | 8 +++- include/ImageViewer.hpp | 4 +- include/QuickMedia.hpp | 5 ++- src/Body.cpp | 9 +++-- src/ImageViewer.cpp | 30 +++++++++++++-- src/QuickMedia.cpp | 100 ++++++++++++++++++++++++++++++++++-------------- 6 files changed, 114 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 859a192..2d88ade 100644 --- a/README.md +++ b/README.md @@ -82,18 +82,22 @@ Type text and then wait and QuickMedia will automatically search.\ ### Local anime search page controls `Ctrl+R`: Mark the anime as watched/unwatched. ### Manga page view controls -`Arrow up`/`Ctrl+K`: Go to the next page (or chapter if the current page is the last one).\ -`Arrow down`/`Ctrl+J`: Go to the previous page (or chapter if the current page is the first one).\ +`Arrow up`/`Ctrl+K`: Go to the previous page (or chapter if the current page is the last one).\ +`Arrow down`/`Ctrl+J`: Go to the next page (or chapter if the current page is the first one).\ `Page up`: Go back 10 pages.\ `Page down`: Go forward 10 pages.\ `Home`: Go to the first page.\ `End`: Go to the last page.\ +`Ctrl+Arrow up`/`Ctrl+Alt+K`: Go to the previous chapter.\ +`Ctrl+Arrow down`/`Ctrl+Alt+J`: Go to the next chapter.\ `F`: Toggle between scaling the image to the window size or only down scaling if the image is too large.\ `I`: Switch to scroll view. ### Manga scroll view controls `Arrow up`/`Ctrl+K`: Move up.\ `Arrow down`/`Ctrl+J`: Move down.\ `Mouse scroll`/`Middle mouse click+Move mouse`: Smoothly scroll.\ +`Ctrl+Arrow up`/`Ctrl+Alt+K`: Go to the previous chapter.\ +`Ctrl+Arrow down`/`Ctrl+Alt+J`: Go to the next chapter.\ `F`: Toggle between scaling the image to the window size or only down scaling if the image is too large.\ `I`: Switch to page view. ### Manga chapters controls diff --git a/include/ImageViewer.hpp b/include/ImageViewer.hpp index c1fb6ad..cb63229 100644 --- a/include/ImageViewer.hpp +++ b/include/ImageViewer.hpp @@ -41,7 +41,9 @@ namespace QuickMedia { enum class ImageViewerAction { NONE, RETURN, - SWITCH_TO_SINGLE_IMAGE_MODE + SWITCH_TO_SINGLE_IMAGE_MODE, + PREVIOUS_CHAPTER, + NEXT_CHAPTER }; class ImageViewer { diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp index 1fda7a3..c1df4ed 100644 --- a/include/QuickMedia.hpp +++ b/include/QuickMedia.hpp @@ -134,8 +134,9 @@ namespace QuickMedia { void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = ""); void save_manga_progress(MangaImagesPage *images_page, Json::Value &json_chapters, Json::Value &json_chapter, int &latest_read); // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter - int image_page(MangaImagesPage *images_page, Body *chapters_body); - void image_continuous_page(MangaImagesPage *images_page); + int image_page(MangaImagesPage *images_page, Body *chapters_body, bool &continue_left_off); + // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter + int image_continuous_page(MangaImagesPage *images_page); void image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body); void chat_login_page(); bool chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room); diff --git a/src/Body.cpp b/src/Body.cpp index dbcaab0..6bf816d 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -1419,7 +1419,7 @@ namespace QuickMedia { window.draw(loading_icon); text_offset_x += body_spacing[body_theme].image_padding_x + item->loaded_image_size.x; } - } else if(item->thumbnail_size.x > 0) { + } else if(draw_thumbnails && item->thumbnail_size.x > 0) { text_offset_x += body_spacing[body_theme].image_padding_x + item->loaded_image_size.x; } @@ -1662,7 +1662,7 @@ namespace QuickMedia { if(item->loaded_image_size.y < 0.1f) item->loaded_image_size = content_size.to_vec2f(); } - } else if(item->thumbnail_size.x > 0) { + } else if(draw_thumbnails && item->thumbnail_size.x > 0) { if(!show_thumbnail) item->loaded_image_size.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 @@ -1670,8 +1670,9 @@ namespace QuickMedia { // image_height = content_size.y; } - const float text_offset_x = body_spacing[body_theme].padding_x + body_spacing[body_theme].image_padding_x + item->loaded_image_size.x; - const float text_max_width = rendering_card_view ? width : (width - text_offset_x - body_spacing[body_theme].image_padding_x); + const float image_padding_x = !draw_thumbnails ? 0.0f : body_spacing[body_theme].image_padding_x; + const float text_offset_x = body_spacing[body_theme].padding_x + image_padding_x + item->loaded_image_size.x; + const float text_max_width = rendering_card_view ? width : (width - text_offset_x - image_padding_x); if(load_texture) update_dirty_state(item, text_max_width); diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index d00c375..1176046 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -194,6 +194,22 @@ namespace QuickMedia { return value >= 0.0 ? 1.0 : -1.0; } + static bool is_key_scroll_up(const mgl::Event::KeyEvent &key) { + return (!key.control && key.code == mgl::Keyboard::Up) || (!key.alt && key.control && key.code == mgl::Keyboard::K); + } + + static bool is_key_scroll_down(const mgl::Event::KeyEvent &key) { + return (!key.control && key.code == mgl::Keyboard::Down) || (!key.alt && key.control && key.code == mgl::Keyboard::J); + } + + static bool is_key_previous_chapter(const mgl::Event::KeyEvent &key) { + return (key.control && key.code == mgl::Keyboard::Up) || (key.alt && key.control && key.code == mgl::Keyboard::K); + } + + static bool is_key_next_chapter(const mgl::Event::KeyEvent &key) { + return (key.control && key.code == mgl::Keyboard::Down) || (key.alt && key.control && key.code == mgl::Keyboard::J); + } + ImageViewerAction ImageViewer::draw() { const double frame_delta = frame_timer.restart(); const double scroll_speed_key_input = 200.0; @@ -229,11 +245,17 @@ namespace QuickMedia { window_size.x = event.size.width; window_size.y = event.size.height; } else if(event.type == mgl::Event::KeyPressed) { - if(event.key.code == mgl::Keyboard::Up || (event.key.control && event.key.code == mgl::Keyboard::K)) + if(is_key_scroll_up(event.key)) up_pressed = true; - if(event.key.code == mgl::Keyboard::Down || (event.key.control && event.key.code == mgl::Keyboard::J)) + if(is_key_scroll_down(event.key)) down_pressed = true; + if(is_key_previous_chapter(event.key)) + return ImageViewerAction::PREVIOUS_CHAPTER; + + if(is_key_next_chapter(event.key)) + return ImageViewerAction::NEXT_CHAPTER; + if(event.key.code == mgl::Keyboard::Escape) return ImageViewerAction::RETURN; @@ -243,9 +265,9 @@ namespace QuickMedia { if(event.key.code == mgl::Keyboard::F) *fit_image_to_window = !*fit_image_to_window; } else if(event.type == mgl::Event::KeyReleased) { - if(event.key.code == mgl::Keyboard::Up || (event.key.control && event.key.code == mgl::Keyboard::K)) + if(is_key_scroll_up(event.key)) up_pressed = false; - if(event.key.code == mgl::Keyboard::Down || (event.key.control && event.key.code == mgl::Keyboard::J)) + if(is_key_scroll_down(event.key)) down_pressed = false; } else if(event.type == mgl::Event::MouseWheelScrolled/* && event.mouse_wheel_scroll.wheel == mgl::Mouse::VerticalWheel*/) { scroll_speed += scroll_speed_mouse_wheel * event.mouse_wheel_scroll.delta * frame_delta; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 4242fa1..a0bd3ea 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1117,11 +1117,17 @@ namespace QuickMedia { auto search_page = std::make_unique(this, plugin_name, "https://mangakatana.com/", false); add_mangakatana_handlers(search_page.get()); - tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + auto bookmarks_body = create_body(); + bookmarks_body->draw_thumbnails = false; + + auto history_body = create_body(); + history_body->draw_thumbnails = false; + + tabs.push_back(Tab{std::move(bookmarks_body), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); - tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{std::move(history_body), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; } else if(strcmp(plugin_name, "mangadex") == 0) { @@ -2192,24 +2198,27 @@ namespace QuickMedia { current_page = pop_page_stack(); } else { while(window.is_open() && (current_page == PageType::IMAGES || current_page == PageType::IMAGES_CONTINUOUS)) { + int page_navigation = 0; + bool continue_left_off = false; + if(current_page == PageType::IMAGES) { - while(current_page == PageType::IMAGES) { - int page_navigation = image_page(manga_images_page, chapters_body); - if(page_navigation == -1) { - // TODO: Make this work if the list is sorted differently than from newest to oldest. - chapters_body->select_next_item(); - select_episode(chapters_body->get_selected(), true); - image_index = 99999; // Start at the page that shows we are at the end of the chapter - manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); - } else if(page_navigation == 1) { - // TODO: Make this work if the list is sorted differently than from newest to oldest. - chapters_body->select_previous_item(); - select_episode(chapters_body->get_selected(), true); - manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); - } - } + page_navigation = image_page(manga_images_page, chapters_body, continue_left_off); } else if(current_page == PageType::IMAGES_CONTINUOUS) { - image_continuous_page(manga_images_page); + page_navigation = image_continuous_page(manga_images_page); + } + + if(page_navigation == -1) { + // TODO: Make this work if the list is sorted differently than from newest to oldest. + chapters_body->select_next_item(); + select_episode(chapters_body->get_selected(), !continue_left_off); + if(!continue_left_off) + image_index = 99999; // Start at the page that shows we are at the end of the chapter + manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); + } else if(page_navigation == 1) { + // TODO: Make this work if the list is sorted differently than from newest to oldest. + chapters_body->select_previous_item(); + select_episode(chapters_body->get_selected(), !continue_left_off); + manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); } } } @@ -3053,7 +3062,9 @@ namespace QuickMedia { bool update_time_pos = false; bool update_duration = false; bool update_window_focus = false; + bool update_window_focus_timer = false; mgl::Clock video_time_pos_clock; + mgl::Clock update_window_focus_time; // HACK! std::string youtube_video_id_dummy; const bool is_youtube = youtube_url_extract_id(video_page->get_url(), youtube_video_id_dummy); @@ -3076,7 +3087,7 @@ namespace QuickMedia { mgl::WindowHandle video_player_window = None; auto on_window_create = [&](mgl::WindowHandle _video_player_window) mutable { video_player_window = _video_player_window; - XSelectInput(disp, video_player_window, KeyPressMask | PointerMotionMask); + XSelectInput(disp, video_player_window, KeyPressMask | PointerMotionMask | FocusChangeMask); redirect_focus_to_video_player_window(video_player_window); XSync(disp, False); @@ -3086,7 +3097,8 @@ namespace QuickMedia { video_player->add_subtitle(subtitle_data.url, subtitle_data.title, "eng"); update_time_pos = true; - update_window_focus = true; + update_window_focus_timer = true; + update_window_focus_time.restart(); }; int64_t youtube_video_content_length = 0; @@ -3336,8 +3348,8 @@ namespace QuickMedia { while (current_page == PageType::VIDEO_CONTENT && window.is_open() && !go_to_previous_page) { while (window.poll_event(event)) { common_event_handler(event); - if(event.type == mgl::Event::GainedFocus && video_player_window) { - redirect_focus_to_video_player_window(video_player_window); + if(event.type == mgl::Event::GainedFocus) { + update_window_focus = true; } else if(event.type == mgl::Event::Resized) { window_size.x = event.size.width; window_size.y = event.size.height; @@ -3358,11 +3370,23 @@ namespace QuickMedia { } handle_x11_events(); + if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, FocusIn, &xev)) {} + + if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, FocusOut, &xev)) { + update_window_focus = true; + } + if(video_player_window && update_window_focus) { update_window_focus = false; redirect_focus_to_video_player_window(video_player_window); } + if(video_player_window && update_window_focus_timer && update_window_focus_time.get_elapsed_time_seconds() >= 0.5) { + update_window_focus_timer = false; + update_window_focus = false; + redirect_focus_to_video_player_window(video_player_window); + } + if(video_player && video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" @@ -3920,9 +3944,10 @@ namespace QuickMedia { } } - int Program::image_page(MangaImagesPage *images_page, Body *chapters_body) { + int Program::image_page(MangaImagesPage *images_page, Body *chapters_body, bool &continue_left_off) { int page_navigation = 0; image_download_cancel = false; + continue_left_off = false; content_cache_dir = get_cache_dir().join(images_page->get_service_name()).join(manga_id_base64).join(base64_url_encode(images_page->get_chapter_name())); if(create_directory_recursive(content_cache_dir) != 0) { @@ -4005,7 +4030,7 @@ namespace QuickMedia { } else if(event.type == mgl::Event::GainedFocus) { redraw = true; } else if(event.type == mgl::Event::KeyPressed) { - if(event.key.code == mgl::Keyboard::Up || (event.key.control && event.key.code == mgl::Keyboard::K)) { + if((!event.key.control && event.key.code == mgl::Keyboard::Up) || (!event.key.alt && event.key.control && event.key.code == mgl::Keyboard::K)) { if(image_index > 0) { --image_index; goto end_of_images_page; @@ -4013,7 +4038,7 @@ namespace QuickMedia { page_navigation = -1; goto end_of_images_page; } - } else if(event.key.code == mgl::Keyboard::Down || (event.key.control && event.key.code == mgl::Keyboard::J)) { + } else if((!event.key.control && event.key.code == mgl::Keyboard::Down) || (!event.key.alt && event.key.control && event.key.code == mgl::Keyboard::J)) { if(image_index < num_manga_pages) { ++image_index; goto end_of_images_page; @@ -4041,6 +4066,12 @@ namespace QuickMedia { image_index = num_manga_pages; goto end_of_images_page; } + } else if((event.key.control && event.key.code == mgl::Keyboard::Up) || (event.key.alt && event.key.control && event.key.code == mgl::Keyboard::K)) { + page_navigation = -1; + goto end_of_images_page; + } else if((event.key.control && event.key.code == mgl::Keyboard::Down) || (event.key.alt && event.key.control && event.key.code == mgl::Keyboard::J)) { + page_navigation = 1; + goto end_of_images_page; } else if(event.key.code == mgl::Keyboard::Escape) { current_page = pop_page_stack(); } else if(event.key.code == mgl::Keyboard::I) { @@ -4130,24 +4161,25 @@ namespace QuickMedia { return page_navigation; } - void Program::image_continuous_page(MangaImagesPage *images_page) { + int Program::image_continuous_page(MangaImagesPage *images_page) { + int page_navigation = 0; image_download_cancel = false; content_cache_dir = get_cache_dir().join(images_page->get_service_name()).join(manga_id_base64).join(base64_url_encode(images_page->get_chapter_name())); if(create_directory_recursive(content_cache_dir) != 0) { show_notification("QuickMedia", "Failed to create directory: " + content_cache_dir.data, Urgency::CRITICAL); current_page = pop_page_stack(); - return; + return page_navigation; } download_chapter_images_if_needed(images_page); if(num_manga_pages == 0) { current_page = pop_page_stack(); - return; + return page_navigation; } if(current_page != PageType::IMAGES_CONTINUOUS || !window.is_open()) - return; + return page_navigation; Json::Value json_chapters; Json::Value json_chapter; @@ -4171,6 +4203,14 @@ namespace QuickMedia { image_view_mode = ImageViewMode::SINGLE; current_page = PageType::IMAGES; break; + case ImageViewerAction::PREVIOUS_CHAPTER: { + page_navigation = -1; + goto end_of_continuous_images_page; + } + case ImageViewerAction::NEXT_CHAPTER: { + page_navigation = 1; + goto end_of_continuous_images_page; + } } AsyncImageLoader::get_instance().update(); window.display(); @@ -4189,8 +4229,10 @@ namespace QuickMedia { } } + end_of_continuous_images_page: window_size.x = window.get_size().x; window_size.y = window.get_size().y; + return page_navigation; } static bool get_image_board_last_posted_filepath(const char *plugin_name, Path &path) { -- cgit v1.2.3