aboutsummaryrefslogtreecommitdiff
path: root/src/ImageViewer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ImageViewer.cpp')
-rw-r--r--src/ImageViewer.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp
new file mode 100644
index 0000000..fcf9519
--- /dev/null
+++ b/src/ImageViewer.cpp
@@ -0,0 +1,249 @@
+#include "../include/ImageViewer.hpp"
+#include "../include/Notification.hpp"
+#include "../include/Storage.hpp"
+#include "../plugins/Manga.hpp"
+#include <cmath>
+#include <SFML/Window/Event.hpp>
+#include <SFML/Graphics/RectangleShape.hpp>
+
+namespace QuickMedia {
+ ImageViewer::ImageViewer(Manga *manga, const std::string &images_url, const std::string &chapter_title, int current_page, const Path &chapter_cache_dir, sf::Font *font) :
+ current_page(current_page),
+ num_pages(0),
+ chapter_title(chapter_title),
+ chapter_cache_dir(chapter_cache_dir),
+ focused_page(current_page),
+ font(font),
+ page_text("", *font, 14)
+ {
+ if(manga->get_number_of_images(images_url, num_pages) != ImageResult::OK) {
+ show_notification("Plugin", "Failed to get number of images", Urgency::CRITICAL);
+ return;
+ }
+ current_page = std::min(current_page, num_pages);
+ image_data.resize(num_pages);
+ page_size.resize(num_pages);
+ for(int i = 0; i < num_pages; ++i) {
+ image_data[i] = nullptr;
+ page_size[i].loaded = false;
+ }
+ page_text.setFillColor(sf::Color::White);
+ }
+
+ bool ImageViewer::render_page(sf::RenderWindow &window, int page, double offset_y) {
+ if(page < 0 || page >= (int)image_data.size())
+ return false;
+
+ const sf::Vector2<double> image_size = get_page_size(page);
+ std::unique_ptr<ImageData> &page_image_data = image_data[page];
+ sf::Vector2<double> render_pos(std::floor(window_size.x * 0.5 - image_size.x * 0.5), std::floor(- image_size.y * 0.5 + scroll + offset_y));
+ if(render_pos.y + image_size.y <= 0.0 || render_pos.y >= window_size.y) {
+ if(page_image_data)
+ page_image_data->visible_on_screen = false;
+ return true;
+ }
+
+ double center_dist = std::abs(window_size.y * 0.5 - (render_pos.y + image_size.y * 0.5));
+ if(center_dist < min_page_center_dist) {
+ min_page_center_dist = center_dist;
+ page_closest_to_center = page;
+ }
+
+ if(page_image_data) {
+ if(page_image_data->failed_to_load_image) {
+ sf::Text error_message("Failed to load image for page " + std::to_string(1 + page), *font, 30);
+ auto text_bounds = error_message.getLocalBounds();
+ error_message.setFillColor(sf::Color::Black);
+ sf::Vector2<double> render_pos_text(std::floor(window_size.x * 0.5 - text_bounds.width * 0.5), std::floor(- text_bounds.height * 0.5 + scroll + offset_y));
+
+ sf::RectangleShape background(sf::Vector2f(image_size.x, image_size.y));
+ background.setFillColor(sf::Color::White);
+ background.setPosition(render_pos.x, render_pos.y);
+ window.draw(background);
+
+ error_message.setPosition(render_pos_text.x, render_pos_text.y);
+ window.draw(error_message);
+ } else {
+ page_image_data->sprite.setPosition(render_pos.x, render_pos.y);
+ window.draw(page_image_data->sprite);
+ }
+ } else {
+ std::string page_str = std::to_string(1 + page);
+
+ sf::Text error_message("Downloading page " + page_str, *font, 30);
+ auto text_bounds = error_message.getLocalBounds();
+ error_message.setFillColor(sf::Color::Black);
+ sf::Vector2<double> render_pos_text(std::floor(window_size.x * 0.5 - text_bounds.width * 0.5), std::floor(- text_bounds.height * 0.5 + scroll + offset_y));
+
+ sf::RectangleShape background(sf::Vector2f(image_size.x, image_size.y));
+ background.setFillColor(sf::Color::White);
+ background.setPosition(render_pos.x, render_pos.y);
+ window.draw(background);
+
+ error_message.setPosition(render_pos_text.x, render_pos_text.y);
+ window.draw(error_message);
+
+ Path image_path = chapter_cache_dir;
+ image_path.join(page_str);
+
+ // TODO: Make image loading asynchronous
+ Path image_finished_path(image_path.data + ".finished");
+ if(get_file_type(image_finished_path) != FileType::FILE_NOT_FOUND && get_file_type(image_path) == FileType::REGULAR) {
+ fprintf(stderr, "ImageViewer: Load page %d\n", 1 + page);
+ page_image_data = std::make_unique<ImageData>();
+ page_image_data->visible_on_screen = true;
+ std::string image_data;
+ if(file_get_content(image_path, image_data) == 0) {
+ if(page_image_data->texture.loadFromMemory(image_data.data(), image_data.size())) {
+ page_image_data->texture.setSmooth(true);
+ page_image_data->sprite.setTexture(page_image_data->texture, true);
+ //image_texture.generateMipmap();
+ page_image_data->failed_to_load_image = false;
+ page_size[page].size = get_page_size(page);
+ page_size[page].loaded = true;
+ } else {
+ page_image_data->failed_to_load_image = true;
+ }
+ } else {
+ show_notification("Manga", "Failed to load image for page " + page_str + ". Image filepath: " + image_path.data, Urgency::CRITICAL);
+ page_image_data->failed_to_load_image = true;
+ }
+ }
+
+ }
+
+ return true;
+ }
+
+ bool ImageViewer::draw(sf::RenderWindow &window) {
+ const double frame_delta = frame_timer.restart().asSeconds();
+ const double scroll_speed_key_input = 450.0;
+ const double scroll_speed_mouse_wheel = 450.0;
+ const double scroll_deaccel = 0.93;
+
+ if(!window_size_set) {
+ auto window_size_i = window.getSize();
+ window_size.x = window_size_i.x;
+ window_size.y = window_size_i.y;
+ window_size_set = true;
+ }
+
+ // TODO: Only redraw when scrolling and when image has finished downloading
+ sf::Event event;
+ while(window.pollEvent(event)) {
+ if (event.type == sf::Event::Closed) {
+ //current_page = Page::EXIT;
+ window.close();
+ return false;
+ } else if(event.type == sf::Event::Resized) {
+ window_size.x = event.size.width;
+ window_size.y = event.size.height;
+ sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
+ window.setView(sf::View(visible_area));
+ //redraw = true;
+ } else if(event.type == sf::Event::GainedFocus) {
+ //redraw = true;
+ } else if(event.type == sf::Event::KeyPressed) {
+ if(event.key.code == sf::Keyboard::Up) {
+ scroll_speed += scroll_speed_key_input * frame_delta;
+ } else if(event.key.code == sf::Keyboard::Down) {
+ scroll_speed -= scroll_speed_key_input * frame_delta;
+ } else if(event.key.code == sf::Keyboard::Escape) {
+ return false;
+ }
+ } else if(event.type == sf::Event::MouseWheelScrolled && event.mouseWheelScroll.wheel == sf::Mouse::VerticalWheel) {
+ scroll_speed += scroll_speed_mouse_wheel * event.mouseWheelScroll.delta * frame_delta;
+ }
+ }
+
+ scroll += scroll_speed;
+ scroll *= scroll_deaccel;
+ if(std::abs(scroll) < 0.1)
+ scroll = 0.0;
+
+ min_page_center_dist = 9999999.0;
+ page_closest_to_center = -1;
+
+ const sf::Vector2<double> selected_page_size = get_page_size(current_page);
+ render_page(window, current_page, window_size.y*0.5);
+ //if(!focused_page_rendered)
+ // return;
+
+ // Render previous pages
+ double page_offset = window_size.y*0.5 - selected_page_size.y*0.5;
+ int page = current_page - 1;
+ while(true) {
+ const sf::Vector2<double> image_size = get_page_size(page);
+ page_offset -= image_size.y*0.5;
+ if(!render_page(window, page, page_offset))
+ break;
+ --page;
+ page_offset -= image_size.y*0.5;
+ }
+
+ // Render next pages
+ page_offset = window_size.y*0.5 + selected_page_size.y*0.5;
+ page = current_page + 1;
+ while(true) {
+ const sf::Vector2<double> image_size = get_page_size(page);
+ page_offset += image_size.y*0.5;
+ if(!render_page(window, page, page_offset))
+ break;
+ ++page;
+ page_offset += image_size.y*0.5;
+ }
+
+ if(page_closest_to_center != -1) {
+ focused_page = page_closest_to_center;
+ }
+
+ if(focused_page != prev_focused_page) {
+ prev_focused_page = focused_page;
+ page_text.setString(chapter_title + " | Page " + std::to_string(1 + focused_page) + "/" + std::to_string(num_pages));
+ }
+
+ const float font_height = page_text.getCharacterSize() + 8.0f;
+ const float background_height = font_height + 6.0f;
+
+ sf::RectangleShape page_text_background(sf::Vector2f(window_size.x, background_height));
+ page_text_background.setFillColor(sf::Color(0, 0, 0, 150));
+ page_text_background.setPosition(0.0f, window_size.y - background_height);
+ window.draw(page_text_background);
+
+ auto page_text_bounds = page_text.getLocalBounds();
+ page_text.setPosition(std::floor(window_size.x * 0.5f - page_text_bounds.width * 0.5f), std::floor(window_size.y - background_height * 0.5f - font_height * 0.5f));
+ window.draw(page_text);
+
+ // Free pages that are not visible on the screen
+ int i = 0;
+ for(auto &page_data : image_data) {
+ if(page_data && !page_data->visible_on_screen) {
+ fprintf(stderr, "ImageViewer: Unload page %d\n", 1 + i);
+ page_data.reset();
+ }
+ ++i;
+ }
+
+ return true;
+ }
+
+ int ImageViewer::get_focused_page() const {
+ return 1 + focused_page;
+ }
+
+ sf::Vector2<double> ImageViewer::get_page_size(int page) {
+ const sf::Vector2<double> no_image_page_size(720.0, 1280.0);
+
+ if(page < 0 || page >= (int)image_data.size())
+ return no_image_page_size;
+
+ if(page_size[page].loaded)
+ return page_size[page].size;
+
+ if(!image_data[page])
+ return no_image_page_size;
+
+ sf::Vector2u texture_size = image_data[page]->texture.getSize();
+ return sf::Vector2<double>(texture_size.x, texture_size.y);
+ }
+} \ No newline at end of file