From 6f11b42b7015646bcdc5f8bbec7da61e76655861 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 10 Sep 2020 20:40:17 +0200 Subject: Add ctrl+r keybind to show related videos menu --- src/Body.cpp | 27 ++++++------- src/QuickMedia.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/Text.cpp | 16 ++++---- 3 files changed, 125 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 6081028..61d100b 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -10,17 +10,17 @@ const sf::Color front_color(43, 45, 47); const sf::Color back_color(33, 35, 37); namespace QuickMedia { - Body::Body(Program *program, sf::Font &font, sf::Font &bold_font) : + Body::Body(Program *program, sf::Font *font, sf::Font *bold_font) : program(program), - title_text("", font, 14), - progress_text("", font, 14), - author_text("", bold_font, 14), - replies_text("", font, 14), + font(font), + bold_font(bold_font), + progress_text("", *font, 14), + author_text("", *bold_font, 14), + replies_text("", *font, 14), selected_item(0), draw_thumbnails(false), loading_thumbnail(false) { - title_text.setFillColor(sf::Color::White); progress_text.setFillColor(sf::Color::White); author_text.setFillColor(sf::Color::White); replies_text.setFillColor(sf::Color(129, 162, 190)); @@ -129,7 +129,6 @@ namespace QuickMedia { } // TODO: Use a render target for the whole body so all images can be put into one. - // TODO: Unload thumbnails once they are no longer visible on the screen. // TODO: Load thumbnails with more than one thread. // TODO: Show chapters (rows) that have been read differently to make it easier to see what hasn't been read yet. void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress) { @@ -163,18 +162,14 @@ namespace QuickMedia { thumbnail_it.second.referenced = false; } - // TODO: Instead of generating a new hash everytime to access textures, cache the hash of the thumbnail url for(auto &body_item : items) { - // Intentionally create the item with the key item->thumbnail_url if it doesn't exist - item_thumbnail_textures[body_item->thumbnail_url].referenced = true; - if(body_item->dirty) { body_item->dirty = false; if(body_item->title_text) body_item->title_text->setString(body_item->title); else - body_item->title_text = std::make_unique(body_item->title, title_text.getFont(), 14, size.x - 50 - image_padding_x * 2.0f); - //body_item->title_text->updateGeometry(); + body_item->title_text = std::make_unique(body_item->title, font, 14, size.x - 50 - image_padding_x * 2.0f); + //body_item->title_text->updateGeometry(); // TODO: Call this to make getHeight work on first frame (called below) } } @@ -211,7 +206,6 @@ namespace QuickMedia { for(int i = first_visible_item + 1; i < num_items; ++i) { const auto &item = items[i]; - auto &item_thumbnail = item_thumbnail_textures[item->thumbnail_url]; if(pos.y >= start_y + size.y) break; @@ -219,6 +213,11 @@ namespace QuickMedia { if(!item->visible) continue; + // TODO: Instead of generating a new hash everytime to access textures, cache the hash of the thumbnail url + // Intentionally create the item with the key item->thumbnail_url if it doesn't exist + item_thumbnail_textures[item->thumbnail_url].referenced = true; + auto &item_thumbnail = item_thumbnail_textures[item->thumbnail_url]; + float item_height = item->title_text->getHeight(); if(!item->author.empty()) { item_height += author_text.getCharacterSize() + 2.0f; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 27926cb..37264d7 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -74,7 +74,9 @@ namespace QuickMedia { fprintf(stderr, "Failed to load font: Lato-Bold.ttf\n"); abort(); } - body = new Body(this, font, bold_font); + body = new Body(this, &font, &bold_font); + related_media_body = new Body(this, &font, &bold_font); + related_media_body->draw_thumbnails = true; struct sigaction action; action.sa_handler = sigpipe_handler; @@ -87,6 +89,7 @@ namespace QuickMedia { } Program::~Program() { + delete related_media_body; delete body; delete current_plugin; if(disp) @@ -584,6 +587,21 @@ namespace QuickMedia { body_size = sf::Vector2f(body_width, window_size.y - search_bottom - body_padding_vertical - tab_h); } + static const float RELATED_MEDIA_WINDOW_WIDTH = 1.0f; + static void get_related_media_body_dimensions(const sf::Vector2f &window_size, sf::Vector2f &body_pos, sf::Vector2f &body_size, float related_videos_text_height) { + float body_padding_horizontal = 25.0f; + float body_padding_vertical = 25.0f; + float body_width = (window_size.x * RELATED_MEDIA_WINDOW_WIDTH) - body_padding_horizontal * 2.0f; + if(body_width <= 480.0f) { + body_width = (window_size.x * RELATED_MEDIA_WINDOW_WIDTH); + body_padding_horizontal = 0.0f; + body_padding_vertical = 10.0f; + } + + body_pos = sf::Vector2f(body_padding_horizontal, body_padding_vertical + related_videos_text_height); + body_size = sf::Vector2f(body_width, window_size.y - body_padding_vertical - related_videos_text_height); + } + void Program::search_suggestion_page() { std::string update_search_text; bool search_running = false; @@ -592,14 +610,14 @@ namespace QuickMedia { std::string autocomplete_text; bool autocomplete_running = false; - Body history_body(this, font, bold_font); + Body history_body(this, &font, &bold_font); std::unique_ptr recommended_body; sf::Text all_tab_text("All", font, tab_text_size); sf::Text history_tab_text("History", font, tab_text_size); sf::Text recommended_tab_text("Recommended", font, tab_text_size); if(current_plugin->name == "youtube") { - recommended_body = std::make_unique(this, font, bold_font); + recommended_body = std::make_unique(this, &font, &bold_font); recommended_body->draw_thumbnails = true; fill_recommended_items_from_json(load_recommended_json(current_plugin), recommended_body->items); } @@ -993,7 +1011,7 @@ namespace QuickMedia { } int saved_recommendation_count = 0; - for(const auto &body_item : related_media) { + for(const auto &body_item : related_media_body->items) { std::string recommended_video_id; if(youtube_url_extract_id(body_item->url, recommended_video_id)) { Json::Value &existing_recommendation = recommended_json[recommended_video_id]; @@ -1036,10 +1054,26 @@ namespace QuickMedia { Page previous_page = pop_page_stack(); std::unique_ptr video_player; + std::unique_ptr related_media_window; + sf::Vector2f related_media_window_size; + bool related_media_window_visible = false; + + sf::Text related_videos_text("Related videos", bold_font, 20); + const float related_videos_text_height = related_videos_text.getCharacterSize(); sf::WindowHandle video_player_window = None; - auto on_window_create = [this, &video_player_window](sf::WindowHandle _video_player_window) mutable { + auto on_window_create = [this, &video_player_window, &related_media_window, &related_media_window_size](sf::WindowHandle _video_player_window) mutable { video_player_window = _video_player_window; + + if(!current_plugin->is_image_board()) { + related_media_window_size.x = window_size.x * RELATED_MEDIA_WINDOW_WIDTH; + related_media_window_size.y = window_size.y; + related_media_window = std::make_unique(sf::VideoMode(related_media_window_size.x, related_media_window_size.y), "", 0); + related_media_window->setVerticalSyncEnabled(true); + related_media_window->setVisible(false); + XReparentWindow(disp, related_media_window->getSystemHandle(), video_player_window, window_size.x - related_media_window_size.x, 0); + } + XSelectInput(disp, video_player_window, KeyPressMask | PointerMotionMask); XSync(disp, False); }; @@ -1055,7 +1089,8 @@ namespace QuickMedia { show_notification("Video player", err_msg.c_str(), Urgency::CRITICAL); current_page = previous_page; } else { - related_media = current_plugin->get_related_media(content_url); + related_media_body->clear_items(); + related_media_body->items = current_plugin->get_related_media(content_url); // TODO: Make this also work for other video plugins if(current_plugin->name != "youtube") @@ -1116,7 +1151,7 @@ namespace QuickMedia { std::string new_video_title; // Find video that hasn't been played before in this video session // TODO: Remove duplicates - for(auto it = related_media.begin(), end = related_media.end(); it != end; ++it) { + for(auto it = related_media_body->items.begin(), end = related_media_body->items.end(); it != end; ++it) { if(watched_videos.find((*it)->url) == watched_videos.end()) { new_video_url = (*it)->url; new_video_title = (*it)->title; @@ -1158,14 +1193,61 @@ namespace QuickMedia { while (current_page == Page::VIDEO_CONTENT) { while (window.pollEvent(event)) { base_event_handler(event, previous_page, true, false, false); + if(event.type == sf::Event::Resized && related_media_window) { + related_media_window_size.x = window_size.x * RELATED_MEDIA_WINDOW_WIDTH; + related_media_window_size.y = window_size.y; + related_media_window->setSize(sf::Vector2u(related_media_window_size.x, related_media_window_size.y)); + related_media_window->setPosition(sf::Vector2i(window_size.x - related_media_window_size.x, 0)); + sf::FloatRect visible_area(0, 0, related_media_window_size.x, related_media_window_size.y); + related_media_window->setView(sf::View(visible_area)); + } + } + + while(related_media_window && related_media_window_visible && related_media_window->pollEvent(event)) { + if(event.type == sf::Event::KeyPressed) { + if(event.key.code == sf::Keyboard::Up) { + related_media_body->select_previous_item(); + } else if(event.key.code == sf::Keyboard::Down) { + related_media_body->select_next_item(); + } else if(event.key.code == sf::Keyboard::Escape) { + related_media_window_visible = false; + related_media_window->setVisible(false); + } else if(event.key.code == sf::Keyboard::R && event.key.control) { + related_media_window_visible = false; + related_media_window->setVisible(related_media_window_visible); + } else if(event.key.code == sf::Keyboard::Enter) { + BodyItem *selected_item = related_media_body->get_selected(); + if(!selected_item) + continue; + + related_media_window.reset(); + related_media_window_visible = false; + + video_player_window = None; + has_video_started = true; + video_player.reset(); + video_player = std::make_unique(current_plugin->use_tor, use_system_mpv_config, video_event_callback, on_window_create); + + content_url = selected_item->url; + content_title = selected_item->title; + load_video_error_check(); + } + } } if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) { KeySym pressed_keysym = XKeycodeToKeysym(disp, xev.xkey.keycode, 0); + bool pressing_ctrl = (CLEANMASK(xev.xkey.state) == ControlMask); if(pressed_keysym == XK_Escape) { current_page = previous_page; - } else if(pressed_keysym == XK_f && CLEANMASK(xev.xkey.state) == ControlMask) { + } else if(pressed_keysym == XK_f && pressing_ctrl) { window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); + } else if(pressed_keysym == XK_r && pressing_ctrl && related_media_window && !related_media_window_visible) { + related_media_window_visible = true; + related_media_window->setVisible(related_media_window_visible); + if(!cursor_visible) + window.setMouseCursorVisible(true); + cursor_visible = true; } } @@ -1199,6 +1281,18 @@ namespace QuickMedia { } if(video_player_window) { + if(related_media_window && related_media_window_visible) { + sf::Vector2f body_pos, body_size; + get_related_media_body_dimensions(window_size, body_pos, body_size, related_videos_text_height); + + related_media_window->clear(back_color); + related_videos_text.setPosition(body_pos.x, 10.0f); + related_media_window->draw(related_videos_text); + related_media_body->draw(*related_media_window, body_pos, body_size); + related_media_window->display(); + continue; + } + if(!cursor_visible) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); continue; @@ -1209,8 +1303,9 @@ namespace QuickMedia { cursor_visible = false; window.setMouseCursorVisible(false); } + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - std::this_thread::sleep_for(std::chrono::milliseconds(50)); } window.setMouseCursorVisible(true); diff --git a/src/Text.cpp b/src/Text.cpp index da21b1d..9ec2f68 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -181,6 +181,14 @@ namespace QuickMedia // Logic loosely based on https://github.com/SFML/SFML/wiki/Source:-CurvedText void Text::updateGeometry(bool update_even_if_not_dirty) { + if(dirtyText) + { + textElements.clear(); + StringViewUtf32 wholeStr(this->str.getData(), this->str.getSize()); + textElements.push_back({ wholeStr, TextElement::Type::TEXT }); + dirtyText = false; + } + if(!update_even_if_not_dirty && !dirty) return; @@ -599,14 +607,6 @@ namespace QuickMedia bool Text::draw(sf::RenderTarget &target) { - if(dirtyText) - { - textElements.clear(); - StringViewUtf32 wholeStr(this->str.getData(), this->str.getSize()); - textElements.push_back({ wholeStr, TextElement::Type::TEXT }); - dirtyText = false; - } - updateGeometry(); if(dirtyCaret || caretMoveDirection != CaretMoveDirection::NONE) -- cgit v1.2.3