aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp27
-rw-r--r--src/QuickMedia.cpp113
-rw-r--r--src/Text.cpp16
3 files changed, 125 insertions, 31 deletions
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<Text>(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<Text>(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<Body> 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<Body>(this, font, bold_font);
+ recommended_body = std::make_unique<Body>(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<VideoPlayer> video_player;
+ std::unique_ptr<sf::RenderWindow> 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::RenderWindow>(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<VideoPlayer>(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)