1
0
Fork 0
mirror of synced 2024-06-27 02:21:05 +12:00

Improved ListView

This commit is contained in:
Rafał Mikrut 2023-11-12 16:00:55 +01:00
parent 186c0e1895
commit c919aa11fa
6 changed files with 171 additions and 112 deletions

View file

@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread::{sleep, JoinHandle}; use std::thread::{sleep, JoinHandle};
use std::time::{Duration, SystemTime}; use std::time::{Duration, Instant, SystemTime};
use std::{fs, thread}; use std::{fs, thread};
#[cfg(feature = "heif")] #[cfg(feature = "heif")]
@ -18,7 +18,7 @@ use image::{DynamicImage, ImageBuffer, Rgb};
use imagepipe::{ImageSource, Pipeline}; use imagepipe::{ImageSource, Pipeline};
#[cfg(feature = "heif")] #[cfg(feature = "heif")]
use libheif_rs::{ColorSpace, HeifContext, RgbChroma}; use libheif_rs::{ColorSpace, HeifContext, RgbChroma};
use log::{info, LevelFilter, Record}; use log::{debug, info, LevelFilter, Record};
// #[cfg(feature = "heif")] // #[cfg(feature = "heif")]
// use libheif_rs::LibHeif; // use libheif_rs::LibHeif;
@ -184,12 +184,17 @@ pub fn get_dynamic_image_from_heic(path: &str) -> Result<DynamicImage> {
} }
pub fn get_dynamic_image_from_raw_image(path: impl AsRef<Path> + std::fmt::Debug) -> Option<DynamicImage> { pub fn get_dynamic_image_from_raw_image(path: impl AsRef<Path> + std::fmt::Debug) -> Option<DynamicImage> {
let mut start_timer = Instant::now();
let mut times = Vec::new();
let file_handler = match OpenOptions::new().read(true).open(&path) { let file_handler = match OpenOptions::new().read(true).open(&path) {
Ok(t) => t, Ok(t) => t,
Err(_e) => { Err(_e) => {
return None; return None;
} }
}; };
times.push(("After opening", start_timer.elapsed()));
start_timer = Instant::now();
let mut reader = BufReader::new(file_handler); let mut reader = BufReader::new(file_handler);
let raw = match rawloader::decode(&mut reader) { let raw = match rawloader::decode(&mut reader) {
@ -199,8 +204,14 @@ pub fn get_dynamic_image_from_raw_image(path: impl AsRef<Path> + std::fmt::Debug
} }
}; };
times.push(("After decoding", start_timer.elapsed()));
start_timer = Instant::now();
let source = ImageSource::Raw(raw); let source = ImageSource::Raw(raw);
times.push(("After creating source", start_timer.elapsed()));
start_timer = Instant::now();
let mut pipeline = match Pipeline::new_from_source(source) { let mut pipeline = match Pipeline::new_from_source(source) {
Ok(pipeline) => pipeline, Ok(pipeline) => pipeline,
Err(_e) => { Err(_e) => {
@ -208,6 +219,9 @@ pub fn get_dynamic_image_from_raw_image(path: impl AsRef<Path> + std::fmt::Debug
} }
}; };
times.push(("After creating pipeline", start_timer.elapsed()));
start_timer = Instant::now();
pipeline.run(None); pipeline.run(None);
let image = match pipeline.output_8bit(None) { let image = match pipeline.output_8bit(None) {
Ok(image) => image, Ok(image) => image,
@ -216,12 +230,22 @@ pub fn get_dynamic_image_from_raw_image(path: impl AsRef<Path> + std::fmt::Debug
} }
}; };
times.push(("After creating image", start_timer.elapsed()));
start_timer = Instant::now();
let Some(image) = ImageBuffer::<Rgb<u8>, Vec<u8>>::from_raw(image.width as u32, image.height as u32, image.data) else { let Some(image) = ImageBuffer::<Rgb<u8>, Vec<u8>>::from_raw(image.width as u32, image.height as u32, image.data) else {
return None; return None;
}; };
times.push(("After creating image buffer", start_timer.elapsed()));
start_timer = Instant::now();
// println!("Properly hashed {:?}", path); // println!("Properly hashed {:?}", path);
Some(DynamicImage::ImageRgb8(image)) let res = Some(DynamicImage::ImageRgb8(image));
times.push(("After creating dynamic image", start_timer.elapsed()));
let str_timer = times.into_iter().map(|(name, time)| format!("{name}: {time:?}")).collect::<Vec<_>>().join(", ");
debug!("Loading raw image --- {str_timer}");
res
} }
pub fn split_path(path: &Path) -> (String, String) { pub fn split_path(path: &Path) -> (String, String) {

View file

@ -1,5 +1,5 @@
use crate::{Callabler, GuiState, MainWindow}; use crate::{Callabler, GuiState, MainWindow};
use czkawka_core::common::IMAGE_RS_EXTENSIONS; use czkawka_core::common::{get_dynamic_image_from_raw_image, IMAGE_RS_EXTENSIONS, RAW_IMAGE_EXTENSIONS};
use image::DynamicImage; use image::DynamicImage;
use log::{debug, error}; use log::{debug, error};
use slint::ComponentHandle; use slint::ComponentHandle;
@ -50,17 +50,33 @@ fn load_image(image_path: &Path) -> Option<(Duration, image::DynamicImage)> {
let image_extension = image_path.extension()?.to_string_lossy().to_lowercase(); let image_extension = image_path.extension()?.to_string_lossy().to_lowercase();
let extension_with_dot = format!(".{}", image_extension); let extension_with_dot = format!(".{}", image_extension);
if !IMAGE_RS_EXTENSIONS.contains(&extension_with_dot.as_str()) { let is_raw_image = RAW_IMAGE_EXTENSIONS.contains(&extension_with_dot.as_str());
let is_normal_image = IMAGE_RS_EXTENSIONS.contains(&extension_with_dot.as_str());
if !is_raw_image && !is_normal_image {
return None; return None;
} }
let load_img_start_timer = Instant::now(); let load_img_start_timer = Instant::now();
let img = image::open(image_name);
match img { // TODO this needs to be run inside closure
Ok(img) => Some((load_img_start_timer.elapsed(), img)), let img = if is_normal_image {
match image::open(image_name) {
Ok(img) => img,
Err(e) => { Err(e) => {
error!("Error while loading image: {}", e); error!("Error while loading image: {}", e);
return None; return None;
} }
} }
} else if is_raw_image {
if let Some(img) = get_dynamic_image_from_raw_image(image_name) {
img
} else {
error!("Error while loading raw image - not sure why - try to guess");
return None;
}
} else {
panic!("Used not supported image extension");
};
Some((load_img_start_timer.elapsed(), img))
} }

View file

@ -7,6 +7,8 @@ component TabItem {
in-out property <CurrentTab> active-tab; in-out property <CurrentTab> active-tab;
in property <string> text; in property <string> text;
in property <CurrentTab> curr_tab; in property <CurrentTab> curr_tab;
callback changed_current_tab();
Rectangle { Rectangle {
width: parent.width; width: parent.width;
horizontal-stretch: 1.0; horizontal-stretch: 1.0;
@ -17,6 +19,7 @@ component TabItem {
return; return;
} }
root.active-tab = root.curr-tab; root.active-tab = root.curr-tab;
changed_current_tab();
} }
} }
} }
@ -61,6 +64,7 @@ component TabItem {
export component LeftSidePanel { export component LeftSidePanel {
in-out property <CurrentTab> active-tab; in-out property <CurrentTab> active-tab;
in-out property <bool> scanning; in-out property <bool> scanning;
callback changed_current_tab();
width: 120px; width: 120px;
VerticalLayout { VerticalLayout {
spacing: 20px; spacing: 20px;
@ -82,6 +86,7 @@ export component LeftSidePanel {
text: "Empty Folders"; text: "Empty Folders";
active-tab <=> root.active-tab; active-tab <=> root.active-tab;
curr_tab: CurrentTab.EmptyFolders; curr_tab: CurrentTab.EmptyFolders;
changed_current_tab() => {root.changed_current_tab();}
} }
TabItem { TabItem {
@ -90,6 +95,7 @@ export component LeftSidePanel {
text: "Empty Files"; text: "Empty Files";
active-tab <=> root.active-tab; active-tab <=> root.active-tab;
curr_tab: CurrentTab.EmptyFiles; curr_tab: CurrentTab.EmptyFiles;
changed_current_tab() => {root.changed_current_tab();}
} }
TabItem { TabItem {
@ -98,6 +104,7 @@ export component LeftSidePanel {
text: "Similar Images"; text: "Similar Images";
active-tab <=> root.active-tab; active-tab <=> root.active-tab;
curr_tab: CurrentTab.SimilarImages; curr_tab: CurrentTab.SimilarImages;
changed_current_tab() => {root.changed_current_tab();}
} }
} }

View file

@ -9,40 +9,43 @@ export component MainList {
in-out property <[MainListModel]> empty_folder_model; in-out property <[MainListModel]> empty_folder_model;
in-out property <[MainListModel]> empty_files_model; in-out property <[MainListModel]> empty_files_model;
in-out property <[MainListModel]> similar_images_model; in-out property <[MainListModel]> similar_images_model;
callback changed_current_tab();
SelectableTableView { empty_folders := SelectableTableView {
visible: root.active-tab == CurrentTab.EmptyFolders; visible: root.active-tab == CurrentTab.EmptyFolders;
min-width: 200px; min-width: 200px;
height: parent.height; height: parent.height;
columns: ["Selection", "Folder Name", "Path"]; columns: ["Selection", "Folder Name", "Path", "Modification Date"];
last-column: "Modification Date"; column-sizes: [35px, 100px, 350px, 150px];
column-sizes: [35px, 100px, 350px, 100px];
values <=> empty-folder-model; values <=> empty-folder-model;
parentPathIdx: 2; parentPathIdx: 2;
fileNameIdx: 1; fileNameIdx: 1;
} }
SelectableTableView { empty_files := SelectableTableView {
visible: root.active-tab == CurrentTab.EmptyFiles; visible: root.active-tab == CurrentTab.EmptyFiles;
min-width: 200px; min-width: 200px;
height: parent.height; height: parent.height;
columns: ["Selection", "File Name", "Path"]; columns: ["Selection", "File Name", "Path", "Modification Date"];
last-column: "Modification Date"; column-sizes: [35px, 100px, 350px, 150px];
column-sizes: [35px, 100px, 350px, 100px];
values <=> empty-files-model; values <=> empty-files-model;
parentPathIdx: 2; parentPathIdx: 2;
fileNameIdx: 1; fileNameIdx: 1;
} }
SelectableTableView { similar_images := SelectableTableView {
visible: root.active-tab == CurrentTab.SimilarImages; visible: root.active-tab == CurrentTab.SimilarImages;
min-width: 200px; min-width: 200px;
height: parent.height; height: parent.height;
columns: ["Selection", "Similarity", "Size", "Dimensions", "File Name", "Path"]; columns: ["Selection", "Similarity", "Size", "Dimensions", "File Name", "Path", "Modification Date"];
last-column: "Modification Date"; column-sizes: [35px, 80px, 80px, 80px, 100px, 350px, 150px];
column-sizes: [35px, 80px, 80px, 80px, 350px, 100px, 100px];
values <=> similar-images-model; values <=> similar-images-model;
parentPathIdx: 5; parentPathIdx: 5;
fileNameIdx: 4; fileNameIdx: 4;
} }
changed_current_tab() => {
empty_folders.deselect_selected_item();
empty_files.deselect_selected_item();
similar_images.deselect_selected_item();
}
} }

View file

@ -53,13 +53,18 @@ export component MainWindow inherits Window {
horizontal-stretch: 0.0; horizontal-stretch: 0.0;
scanning <=> root.scanning; scanning <=> root.scanning;
active-tab <=> root.active-tab; active-tab <=> root.active-tab;
changed_current_tab() => {
GuiState.preview-visible = false;
main_list.changed_current_tab();
}
} }
VerticalLayout { VerticalLayout {
horizontal-stretch: 1.0; horizontal-stretch: 1.0;
Rectangle { Rectangle {
vertical-stretch: 1.0; vertical-stretch: 1.0;
MainList { main_list := MainList {
x: 0;
width: GuiState.preview_visible ? parent.width / 2 : parent.width; width: GuiState.preview_visible ? parent.width / 2 : parent.width;
height: parent.height; height: parent.height;
horizontal-stretch: 0.5; horizontal-stretch: 0.5;
@ -74,6 +79,7 @@ export component MainWindow inherits Window {
width: GuiState.preview_visible ? parent.width / 2 : 0; width: GuiState.preview_visible ? parent.width / 2 : 0;
visible: GuiState.preview_visible; visible: GuiState.preview_visible;
source: GuiState.preview_image; source: GuiState.preview_image;
image-fit: ImageFit.contain;
} }
} }

View file

@ -8,7 +8,6 @@ import {GuiState} from "gui_state.slint";
export component SelectableTableView inherits Rectangle { export component SelectableTableView inherits Rectangle {
callback item_opened(string); callback item_opened(string);
in property <[string]> columns; in property <[string]> columns;
in property <string> last_column;
in-out property <[MainListModel]> values; in-out property <[MainListModel]> values;
in-out property <[length]> column_sizes; in-out property <[length]> column_sizes;
private property <int> column_number: column-sizes.length + 1; private property <int> column_number: column-sizes.length + 1;
@ -25,6 +24,7 @@ export component SelectableTableView inherits Rectangle {
} }
} }
ScrollView {
VerticalBox { VerticalBox {
padding: 5px; padding: 5px;
forward-focus: focus-item; forward-focus: focus-item;
@ -65,11 +65,6 @@ export component SelectableTableView inherits Rectangle {
} }
} }
} }
Text {
overflow: elide;
text: last-column;
}
} }
list_view := ListView { list_view := ListView {
@ -141,3 +136,11 @@ export component SelectableTableView inherits Rectangle {
} }
} }
} }
public function deselect_selected_item() {
if (root.selected_item != -1) {
root.values[root.selected-item].selected_row = false;
root.selected-item = -1;
}
}
}