diff --git a/Cargo.lock b/Cargo.lock index c0d30aa..719c085 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,10 +441,10 @@ dependencies = [ "directories-next", "futures", "gdk", - "gio", "glib", "gtk", "humansize", + "image", "open", ] diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index 2315996..743ad64 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -11,7 +11,6 @@ repository = "https://github.com/qarmin/czkawka" [dependencies] czkawka_core = { path = "../czkawka_core" } gdk = "0.13.2" -gio = "0.9.1" glib = "0.10.1" humansize = "1" @@ -29,6 +28,9 @@ directories-next = "2.0.0" # For opening files open = "1.4.0" +# To get image preview +image = "0.23" + [dependencies.gtk] version = "0.9.2" default-features = false # just in case diff --git a/czkawka_gui/czkawka.glade b/czkawka_gui/czkawka.glade index 6a0d308..15f1470 100644 --- a/czkawka_gui/czkawka.glade +++ b/czkawka_gui/czkawka.glade @@ -1438,17 +1438,43 @@ Author: Rafał Mikrut True False - vertical True False - 8 + vertical - + True False - Minimal file size(in bytes) + 8 + + + True + False + Minimal file size(in bytes) + + + False + True + 0 + + + + + True + True + 15 + 16384 + False + number + + + True + True + 1 + + False @@ -1457,118 +1483,137 @@ Author: Rafał Mikrut - + True - True - 15 - 16384 - False - number + False + + + True + False + Similarity level + + + False + True + 0 + + + + + Very Small + True + True + False + True + radio_button_similar_images_very_high + + + False + True + 1 + + + + + Small + True + True + False + True + radio_button_similar_images_very_high + + + False + True + 2 + + + + + Medium + True + True + False + True + radio_button_similar_images_very_high + + + False + True + 3 + + + + + High + True + True + False + True + radio_button_similar_images_very_high + + + False + True + 4 + + + + + Very High + True + True + False + True + True + + + False + True + 5 + + - True + False True 1 + + + True + True + in + + + + + + True + True + 2 + + - False + True True 0 - + True False - + + 100 + 80 True False - Similarity level + gtk-missing-image - - False - True - 0 - - - - - Very Small - True - True - False - True - radio_button_similar_images_very_high - - - False - True - 1 - - - - - Small - True - True - False - True - radio_button_similar_images_very_high - - - False - True - 2 - - - - - Medium - True - True - False - True - radio_button_similar_images_very_high - - - False - True - 3 - - - - - High - True - True - False - True - True - radio_button_similar_images_very_high - - - False - True - 4 - - - - - Very High - True - True - False - True - True - - - False - True - 5 - @@ -1577,21 +1622,6 @@ Author: Rafał Mikrut 1 - - - True - True - in - - - - - - True - True - 2 - - 5 diff --git a/czkawka_gui/src/connect_button_search.rs b/czkawka_gui/src/connect_button_search.rs index b75300f..b719c72 100644 --- a/czkawka_gui/src/connect_button_search.rs +++ b/czkawka_gui/src/connect_button_search.rs @@ -74,6 +74,7 @@ pub fn connect_button_search( let grid_progress_stages = gui_data.grid_progress_stages.clone(); let progress_bar_current_stage = gui_data.progress_bar_current_stage.clone(); let progress_bar_all_stages = gui_data.progress_bar_all_stages.clone(); + let image_preview_similar_images = gui_data.image_preview_similar_images.clone(); buttons_search_clone.connect_clicked(move |_| { let included_directories = get_string_from_list_store(&scrolled_window_included_directories); @@ -241,6 +242,8 @@ pub fn connect_button_search( }); } "notebook_main_similar_images_finder_label" => { + image_preview_similar_images.hide(); + label_stage.show(); grid_progress_stages.show_all(); dialog_progress.resize(1, 1); diff --git a/czkawka_gui/src/gui_data.rs b/czkawka_gui/src/gui_data.rs index e21c177..d8b2559 100644 --- a/czkawka_gui/src/gui_data.rs +++ b/czkawka_gui/src/gui_data.rs @@ -1,4 +1,3 @@ -extern crate gdk; extern crate gtk; use crossbeam_channel::unbounded; use czkawka_core::big_file::BigFile; @@ -149,6 +148,9 @@ pub struct GuiData { pub button_stop_in_dialog: gtk::Button, + //// Similar Images + pub image_preview_similar_images: gtk::Image, + //// Settings pub check_button_settings_save_at_exit: gtk::CheckButton, pub check_button_settings_load_at_start: gtk::CheckButton, @@ -354,6 +356,9 @@ impl GuiData { let button_stop_in_dialog: gtk::Button = builder.get_object("button_stop_in_dialog").unwrap(); + //// Similar Images + let image_preview_similar_images: gtk::Image = builder.get_object("image_preview_similar_images").unwrap(); + //// Settings let check_button_settings_save_at_exit: gtk::CheckButton = builder.get_object("check_button_settings_save_at_exit").unwrap(); let check_button_settings_load_at_start: gtk::CheckButton = builder.get_object("check_button_settings_load_at_start").unwrap(); @@ -457,6 +462,7 @@ impl GuiData { label_stage, grid_progress_stages, button_stop_in_dialog, + image_preview_similar_images, check_button_settings_save_at_exit, check_button_settings_load_at_start, check_button_settings_confirm_deletion, diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index c8706b5..45e0127 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -2,8 +2,14 @@ use crate::create_tree_view::*; use crate::double_click_opening::*; use crate::gui_data::*; use crate::help_functions::*; +use directories_next::ProjectDirs; use gtk::prelude::*; use gtk::{SelectionMode, TreeView}; +use image::imageops::FilterType; +use image::GenericImageView; +use std::cmp::Ordering; +use std::fs; +use std::path::Path; pub fn initialize_gui(gui_data: &GuiData) { //// Setup default look(duplicate finder) @@ -22,6 +28,7 @@ pub fn initialize_gui(gui_data: &GuiData) { let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone(); let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone(); let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone(); + let image_preview_similar_images = gui_data.image_preview_similar_images.clone(); // Disable and show buttons buttons_search.show(); @@ -121,6 +128,8 @@ pub fn initialize_gui(gui_data: &GuiData) { } // Similar Images { + image_preview_similar_images.hide(); + let col_types: [glib::types::Type; 9] = [ glib::types::Type::String, glib::types::Type::String, @@ -142,6 +151,79 @@ pub fn initialize_gui(gui_data: &GuiData) { create_tree_view_similar_images(&mut tree_view); tree_view.connect_button_press_event(opening_double_click_function_similar_images); + tree_view.connect_button_release_event(move |tree_view, event| { + if event.get_event_type() == gdk::EventType::DoubleButtonPress { + common_open_function(tree_view, ColumnsSimilarImages::Name as i32, ColumnsSimilarImages::Path as i32); + } + + let (selected_rows, tree_model) = tree_view.get_selection().get_selected_rows(); + + let mut created_image = false; + + if !selected_rows.is_empty() { + let tree_path = selected_rows[0].clone(); + if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") { + // TODO labels on {} are in testing stage, so we just ignore for now this warning until found better idea how to fix this + #[allow(clippy::never_loop)] + 'dir: loop { + let cache_dir = proj_dirs.cache_dir(); + if cache_dir.exists() { + if !cache_dir.is_dir() { + break 'dir; + } + } else if fs::create_dir(cache_dir).is_err() { + break 'dir; + } + let path = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), ColumnsSimilarImages::Path as i32).get::().unwrap().unwrap(); + let name = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), ColumnsSimilarImages::Name as i32).get::().unwrap().unwrap(); + + let file_name = format!("{}/{}", path, name); //"/home/rafal/Pulpit/karl-fitzgerald-4.jpg"; + let file_name = file_name.as_str(); + + if let Some(extension) = Path::new(file_name).extension() { + let img = match image::open(&file_name) { + Ok(t) => t, + Err(_) => { + break 'dir; + } + }; + let ratio = img.width() / img.height(); + let requested_dimensions = (400, 400); + let new_size; + match ratio.cmp(&(requested_dimensions.0 / requested_dimensions.1)) { + Ordering::Greater => { + new_size = (requested_dimensions.0, (img.height() * requested_dimensions.0) / img.width()); + } + Ordering::Less => { + new_size = ((img.width() * requested_dimensions.1) / img.height(), requested_dimensions.1); + } + Ordering::Equal => { + new_size = requested_dimensions; + } + } + let img = img.resize(new_size.0, new_size.1, FilterType::Triangle); + let file_dir = cache_dir.join(format!("cached_file.{}", extension.to_string_lossy())); + if img.save(&file_dir).is_err() { + break 'dir; + } + let string_dir = file_dir.to_string_lossy().to_string(); + image_preview_similar_images.set_from_file(string_dir); + created_image = true; + } + break 'dir; + } + } + } + if created_image { + image_preview_similar_images.show(); + } else { + image_preview_similar_images.hide(); + } + + gtk::Inhibit(false) + }); + + // tree_view.connect_button_press_event(opening_double_click_function_similar_images); scrolled_window_similar_images_finder.add(&tree_view); scrolled_window_similar_images_finder.show_all();