aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--TODO3
-rw-r--r--src/QuickMedia.cpp97
3 files changed, 88 insertions, 16 deletions
diff --git a/README.md b/README.md
index c1aa4be..2678619 100644
--- a/README.md
+++ b/README.md
@@ -136,6 +136,10 @@ Type text and then wait and QuickMedia will automatically search.\
`Ctrl+I`: Reverse image search the selected image or select an url to open in the browser.\
`Arrow left/right`: Move captcha slider left/right.\
`Ctrl+S`: Save the image/video attached to the selected post.
+### 4chan image controls
+`Mouse scroll`: Zoom.\
+`Left mouse button + move`: Pan (move) the image.\
+`W`: Reset zoom and panning, scaling image to window size.
### File save controls
`Tab`: Switch between navigating the file manager and file name.\
`Ctrl+Enter`/`Click on save`: Save the file.\
diff --git a/TODO b/TODO
index 2697269..4ce55f7 100644
--- a/TODO
+++ b/TODO
@@ -197,4 +197,5 @@ Add audio-only mode for peertube (without also downloading video).
Add option to play peertube video directly from url, along with timestamp. Should also work for playlists.
Peertube urls should play directly in quickmedia.
Test peertube with live streams.
-Peertube hls streams can be really slow to start up (especially for videos.autizmo.xyz). This is an issue in ffmpeg. Maybe use youtube proxy downloader for this? those videos are fragmented. \ No newline at end of file
+Peertube hls streams can be really slow to start up (especially for videos.autizmo.xyz). This is an issue in ffmpeg. Maybe use youtube proxy downloader for this? those videos are fragmented.
+Add keybindings for image control for 4chan. \ No newline at end of file
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 258249b..d91f2a1 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -3821,6 +3821,22 @@ namespace QuickMedia {
return true;
}
+ struct ImageControl {
+ float zoom = 1.0f;
+ bool pressed = false;
+ bool moved = false;
+ sf::Vector2f offset; // relative to center
+ sf::Vector2i prev_mouse_pos;
+ };
+
+ static sf::Vector2f to_vec2f(sf::Vector2i vec) {
+ return sf::Vector2f(vec.x, vec.y);
+ }
+
+ static sf::Vector2f to_vec2f(sf::Vector2u vec) {
+ return sf::Vector2f(vec.x, vec.y);
+ }
+
void Program::image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body) {
// TODO: Instead of using stage here, use different pages for each stage
enum class NavigationStage {
@@ -3844,6 +3860,8 @@ namespace QuickMedia {
std::string attached_image_url;
ImageBoardCaptchaChallenge captcha_challenge;
+ ImageControl image_control;
+
captcha_texture.setSmooth(true);
captcha_bg_texture.setSmooth(true);
@@ -4048,17 +4066,19 @@ namespace QuickMedia {
} else {
BodyItem *selected_item = thread_body->get_selected();
if(selected_item && !selected_item->url.empty()) {
- navigation_stage = NavigationStage::VIEWING_ATTACHED_IMAGE;
attached_image_url = selected_item->url;
sf::Image image;
TaskResult task_result = run_task_with_loading_screen([&attached_image_url, &image]{
- std::string image_data;
- if(download_to_string_cache(attached_image_url, image_data, {}) != DownloadResult::OK) {
+ SHA256 sha256;
+ sha256.add(attached_image_url.data(), attached_image_url.size());
+ Path media_file_path = get_cache_dir().join("media").join(sha256.getHash());
+
+ if(get_file_type(media_file_path) == FileType::FILE_NOT_FOUND && download_to_file(attached_image_url, media_file_path.data, {}, true) != DownloadResult::OK) {
show_notification("QuickMedia", "Failed to download image: " + attached_image_url, Urgency::CRITICAL);
return false;
}
- if(!load_image_from_memory(image, image_data.data(), image_data.size())) {
+ if(!load_image_from_file(image, media_file_path.data)) {
show_notification("QuickMedia", "Failed to load image: " + attached_image_url, Urgency::CRITICAL);
return false;
}
@@ -4070,7 +4090,16 @@ namespace QuickMedia {
if(attached_image_texture->loadFromImage(image)) {
attached_image_texture->setSmooth(true);
attached_image_sprite.setTexture(*attached_image_texture, true);
+ attached_image_sprite.setOrigin(0.0f, 0.0f);
+ attached_image_sprite.setScale(1.0f, 1.0f);
navigation_stage = NavigationStage::VIEWING_ATTACHED_IMAGE;
+
+ image_control.zoom = 1.0f;
+ image_control.offset = to_vec2f(attached_image_texture->getSize()) * 0.5f;
+ image_control.pressed = sf::Mouse::isButtonPressed(sf::Mouse::Left);
+ image_control.moved = false;
+ if(image_control.pressed)
+ image_control.prev_mouse_pos = sf::Mouse::getPosition(window);
} else {
show_notification("QuickMedia", "Failed to load image: " + attached_image_url, Urgency::CRITICAL);
}
@@ -4214,6 +4243,36 @@ namespace QuickMedia {
}
}
+ if(navigation_stage == NavigationStage::VIEWING_ATTACHED_IMAGE) {
+ if(event.type == sf::Event::MouseWheelScrolled) {
+ image_control.zoom *= (1.0f + event.mouseWheelScroll.delta * 0.1f);
+ if(image_control.zoom < 0.01f)
+ image_control.zoom = 0.01f;
+ image_control.moved = true;
+ } else if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
+ image_control.pressed = true;
+ image_control.prev_mouse_pos.x = event.mouseButton.x;
+ image_control.prev_mouse_pos.y = event.mouseButton.y;
+ } else if(event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) {
+ image_control.pressed = false;
+ } else if(event.type == sf::Event::MouseMoved && image_control.pressed) {
+ const sf::Vector2i mouse_diff = sf::Vector2i(event.mouseMove.x, event.mouseMove.y) - image_control.prev_mouse_pos;
+ image_control.prev_mouse_pos.x = event.mouseMove.x;
+ image_control.prev_mouse_pos.y = event.mouseMove.y;
+ image_control.offset -= (to_vec2f(mouse_diff) / image_control.zoom);
+ image_control.moved = true;
+ idle_active_handler();
+ } else if(event.type == sf::Event::KeyPressed) {
+ if(event.key.code == sf::Keyboard::W) {
+ image_control.zoom = 1.0f;
+ image_control.moved = false;
+ image_control.offset = to_vec2f(attached_image_texture->getSize()) * 0.5f;
+ attached_image_sprite.setOrigin(0.0f, 0.0f);
+ attached_image_sprite.setScale(1.0f, 1.0f);
+ }
+ }
+ }
+
if(event.type == sf::Event::KeyPressed && navigation_stage == NavigationStage::VIEWING_ATTACHED_IMAGE) {
if(event.key.code == sf::Keyboard::Escape || event.key.code == sf::Keyboard::BackSpace) {
navigation_stage = NavigationStage::VIEWING_COMMENTS;
@@ -4440,17 +4499,25 @@ namespace QuickMedia {
window.draw(captcha_solution_text);
} else if(navigation_stage == NavigationStage::VIEWING_ATTACHED_IMAGE) {
if(attached_image_texture->getNativeHandle() != 0) {
- auto content_size = window_size;
- sf::Vector2u texture_size = attached_image_texture->getSize();
- sf::Vector2f texture_size_f(texture_size.x, texture_size.y);
- auto image_scale = get_ratio(texture_size_f, clamp_to_size(texture_size_f, content_size));
- attached_image_sprite.setScale(image_scale);
-
- auto image_size = texture_size_f;
- image_size.x *= image_scale.x;
- image_size.y *= image_scale.y;
- attached_image_sprite.setPosition(std::floor(content_size.x * 0.5f - image_size.x * 0.5f), std::floor(content_size.y * 0.5f - image_size.y * 0.5f));
- window.draw(attached_image_sprite);
+ if(image_control.moved) {
+ attached_image_sprite.setOrigin(image_control.offset);
+ attached_image_sprite.setScale(image_control.zoom, image_control.zoom);
+ attached_image_sprite.setPosition(window_size * 0.5f);
+ window.draw(attached_image_sprite);
+ } else {
+ auto content_size = window_size;
+ sf::Vector2u texture_size = attached_image_texture->getSize();
+ sf::Vector2f texture_size_f(texture_size.x, texture_size.y);
+ auto image_scale = get_ratio(texture_size_f, clamp_to_size(texture_size_f, content_size));
+ image_control.zoom = std::min(image_scale.x, image_scale.y);
+ attached_image_sprite.setScale(image_scale);
+
+ auto image_size = texture_size_f;
+ image_size.x *= image_scale.x;
+ image_size.y *= image_scale.y;
+ attached_image_sprite.setPosition(std::floor(content_size.x * 0.5f - image_size.x * 0.5f), std::floor(content_size.y * 0.5f - image_size.y * 0.5f));
+ window.draw(attached_image_sprite);
+ }
} else {
sf::RectangleShape rect(sf::Vector2f(640.0f, 480.0f));
rect.setFillColor(get_theme().image_loading_background_color);