From 04dba35c335f9f856ef061687512e285d8e5c4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= Date: Sun, 11 Feb 2024 11:54:48 +0100 Subject: [PATCH] Added popup delete --- krokiet/src/common.rs | 4 +- krokiet/src/connect_select.rs | 170 ++++++++++++++++---------------- krokiet/ui/action_buttons.slint | 20 ++-- krokiet/ui/main_window.slint | 11 +++ krokiet/ui/popup_delete.slint | 73 ++++++++++++++ 5 files changed, 182 insertions(+), 96 deletions(-) create mode 100644 krokiet/ui/popup_delete.slint diff --git a/krokiet/src/common.rs b/krokiet/src/common.rs index 8f29d84..2243774 100644 --- a/krokiet/src/common.rs +++ b/krokiet/src/common.rs @@ -38,14 +38,14 @@ pub fn get_int_size_idx(active_tab: CurrentTab) -> usize { } } -pub fn get_width_idx(active_tab: CurrentTab) -> usize { +pub fn get_int_width_idx(active_tab: CurrentTab) -> usize { match active_tab { CurrentTab::SimilarImages => 4, CurrentTab::Settings => panic!("Button should be disabled"), _ => panic!("Unable to get height from this tab"), } } -pub fn get_height_idx(active_tab: CurrentTab) -> usize { +pub fn get_int_height_idx(active_tab: CurrentTab) -> usize { match active_tab { CurrentTab::SimilarImages => 5, CurrentTab::Settings => panic!("Button should be disabled"), diff --git a/krokiet/src/connect_select.rs b/krokiet/src/connect_select.rs index 384ec40..78e6da4 100644 --- a/krokiet/src/connect_select.rs +++ b/krokiet/src/connect_select.rs @@ -1,4 +1,6 @@ -use crate::common::{connect_i32_into_u64, get_int_size_idx, get_is_header_mode, get_tool_model, set_tool_model}; +use crate::common::{ + connect_i32_into_u64, get_int_height_idx, get_int_modification_date_idx, get_int_size_idx, get_int_width_idx, get_is_header_mode, get_tool_model, set_tool_model, +}; use crate::{Callabler, GuiState, MainListModel, MainWindow, SelectMode}; use crate::{CurrentTab, SelectModel}; use slint::{ComponentHandle, Model, ModelRc, VecModel}; @@ -16,9 +18,12 @@ pub fn connect_select(app: &MainWindow) { SelectMode::SelectAll => select_all(current_model), SelectMode::UnselectAll => deselect_all(current_model), SelectMode::InvertSelection => invert_selection(current_model), - SelectMode::SelectTheBiggestSize => select_the_biggest_size(current_model, active_tab), - SelectMode::SelectTheSmallestSize => select_the_small_size(current_model, active_tab), - _ => unimplemented!(), + SelectMode::SelectTheBiggestSize => select_by_size_date(current_model, active_tab, true, true), + SelectMode::SelectTheSmallestSize => select_by_size_date(current_model, active_tab, false, true), + SelectMode::SelectTheBiggestResolution => select_by_resolution(current_model, active_tab, true), + SelectMode::SelectTheSmallestResolution => select_by_resolution(current_model, active_tab, false), + SelectMode::SelectNewest => select_by_size_date(current_model, active_tab, true, false), + SelectMode::SelectOldest => select_by_size_date(current_model, active_tab, false, false), }; set_tool_model(&app, active_tab, new_model); }); @@ -77,51 +82,93 @@ fn translate_select_mode(select_mode: SelectMode) -> String { } } -fn select_the_biggest_size(model: ModelRc, active_tab: CurrentTab) -> ModelRc { +// TODO, when model will be able to contain i64 instead two i32, this function could be merged with select_by_size_date +fn select_by_resolution(model: ModelRc, active_tab: CurrentTab, biggest: bool) -> ModelRc { let is_header_mode = get_is_header_mode(active_tab); - assert!(is_header_mode); // non header modes not really have reasont to use this function + assert!(is_header_mode); // non header modes not really have reason to use this function let mut old_data = model.iter().collect::>(); let headers_idx = find_header_idx_and_deselect_all(&mut old_data); - let size_idx = get_int_size_idx(active_tab); + let width_idx = get_int_width_idx(active_tab); + let height_idx = get_int_height_idx(active_tab); - for i in 0..(headers_idx.len() - 1) { - let mut max_size = 0; - let mut max_size_idx = 0; - for j in (headers_idx[i] + 1)..headers_idx[i + 1] { - let int_data = old_data[j].val_int.iter().collect::>(); - let size = connect_i32_into_u64(int_data[size_idx], int_data[size_idx + 1]); - if size > max_size { - max_size = size; - max_size_idx = j; + if biggest { + for i in 0..(headers_idx.len() - 1) { + let mut max_item = 0; + let mut max_item_idx = 0; + #[allow(clippy::needless_range_loop)] + for j in (headers_idx[i] + 1)..headers_idx[i + 1] { + let int_data = old_data[j].val_int.iter().collect::>(); + let item = int_data[width_idx] * int_data[height_idx]; + if item > max_item { + max_item = item; + max_item_idx = j; + } } + old_data[max_item_idx].checked = true; + } + } else { + for i in 0..(headers_idx.len() - 1) { + let mut min_item = u64::MAX; + let mut min_item_idx = 0; + #[allow(clippy::needless_range_loop)] + for j in (headers_idx[i] + 1)..headers_idx[i + 1] { + let int_data = old_data[j].val_int.iter().collect::>(); + let item = (int_data[width_idx] * int_data[height_idx]) as u64; + if item < min_item { + min_item = item; + min_item_idx = j; + } + } + old_data[min_item_idx].checked = true; } - old_data[max_size_idx].checked = true; } ModelRc::new(VecModel::from(old_data)) } -fn select_the_small_size(model: ModelRc, active_tab: CurrentTab) -> ModelRc { +fn select_by_size_date(model: ModelRc, active_tab: CurrentTab, biggest_newest: bool, size: bool) -> ModelRc { let is_header_mode = get_is_header_mode(active_tab); - assert!(is_header_mode); // non header modes not really have reasont to use this function + assert!(is_header_mode); // non header modes not really have reason to use this function let mut old_data = model.iter().collect::>(); let headers_idx = find_header_idx_and_deselect_all(&mut old_data); - let size_idx = get_int_size_idx(active_tab); + let item_idx = if size { + get_int_size_idx(active_tab) + } else { + get_int_modification_date_idx(active_tab) + }; - for i in 0..(headers_idx.len() - 1) { - let mut min_size = u64::MAX; - let mut min_size_idx = 0; - for j in (headers_idx[i] + 1)..headers_idx[i + 1] { - let int_data = old_data[j].val_int.iter().collect::>(); - let size = connect_i32_into_u64(int_data[size_idx], int_data[size_idx + 1]); - if size < min_size { - min_size = size; - min_size_idx = j; + if biggest_newest { + for i in 0..(headers_idx.len() - 1) { + let mut max_item = 0; + let mut max_item_idx = 0; + #[allow(clippy::needless_range_loop)] + for j in (headers_idx[i] + 1)..headers_idx[i + 1] { + let int_data = old_data[j].val_int.iter().collect::>(); + let item = connect_i32_into_u64(int_data[item_idx], int_data[item_idx + 1]); + if item > max_item { + max_item = item; + max_item_idx = j; + } } + old_data[max_item_idx].checked = true; + } + } else { + for i in 0..(headers_idx.len() - 1) { + let mut min_item = u64::MAX; + let mut min_item_idx = 0; + #[allow(clippy::needless_range_loop)] + for j in (headers_idx[i] + 1)..headers_idx[i + 1] { + let int_data = old_data[j].val_int.iter().collect::>(); + let item = connect_i32_into_u64(int_data[item_idx], int_data[item_idx + 1]); + if item < min_item { + min_item = item; + min_item_idx = j; + } + } + old_data[min_item_idx].checked = true; } - old_data[min_size_idx].checked = true; } ModelRc::new(VecModel::from(old_data)) @@ -129,11 +176,11 @@ fn select_the_small_size(model: ModelRc, active_tab: CurrentTab) fn select_all(model: ModelRc) -> ModelRc { let mut old_data = model.iter().collect::>(); - old_data.iter_mut().for_each(|x| { + for x in &mut old_data { if !x.header_row { - x.checked = true + x.checked = true; } - }); + } ModelRc::new(VecModel::from(old_data)) } @@ -145,15 +192,15 @@ fn deselect_all(model: ModelRc) -> ModelRc { fn invert_selection(model: ModelRc) -> ModelRc { let mut old_data = model.iter().collect::>(); - old_data.iter_mut().for_each(|x| { + for x in &mut old_data { if !x.header_row { - x.checked = !x.checked + x.checked = !x.checked; } - }); + } ModelRc::new(VecModel::from(old_data)) } -fn find_header_idx_and_deselect_all(old_data: &mut Vec) -> Vec { +fn find_header_idx_and_deselect_all(old_data: &mut [MainListModel]) -> Vec { let mut header_idx = old_data .iter() .enumerate() @@ -161,55 +208,10 @@ fn find_header_idx_and_deselect_all(old_data: &mut Vec) -> Vec>(); header_idx.push(old_data.len()); - old_data.iter_mut().for_each(|x| { + for x in old_data.iter_mut() { if !x.header_row { x.checked = false; } - }); + } header_idx } - -#[cfg(test)] -mod test { - use crate::{MainListModel, SelectMode}; - use slint::ModelRc; - - // #[test] - // pub fn test_select_all() { - // let model = ModelRc::new(VecModel::from(vec![SelectModel { - // name: "test".into(), - // data: SelectMode::SelectAll, - // }])); - // let new_model = select_all(model); - // let new_data = new_model.iter().collect::>(); - // assert_eq!(new_data[0].checked, true); - // } - // - // fn prepare_simple_model() -> ModelRc { - // ModelRc::new(VecModel::from(vec![ - // MainListModel { - // header_row: false, - // checked: false, - // selected_row: false, - // val_str: [], - // val_int: [0, 0, 0, 0, 0, 0], - // }, - // MainListModel { - // header_row: false, - // checked: true, - // text: "test".into(), - // size: 0, - // resolution: (0, 0), - // date: 0, - // }, - // MainListModel { - // header_row: false, - // checked: false, - // text: "test".into(), - // size: 0, - // resolution: (0, 0), - // date: 0, - // }, - // ])) - // } -} diff --git a/krokiet/ui/action_buttons.slint b/krokiet/ui/action_buttons.slint index e052fb8..b13dcfa 100644 --- a/krokiet/ui/action_buttons.slint +++ b/krokiet/ui/action_buttons.slint @@ -21,6 +21,7 @@ export component ActionButtons inherits HorizontalLayout { callback scan_stopping; callback scan_starting(CurrentTab); callback show_select_popup(length, length); + callback show_remove_popup(); in-out property bottom_panel_visibility: BottomPanelVisibility.Directories; in-out property stop_requested: false; in-out property scanning; @@ -57,16 +58,6 @@ export component ActionButtons inherits HorizontalLayout { horizontal-stretch: 0.5; } - delete_button := Button { - height: parent.height; - enabled: !scanning && lists_enabled; - text: "Delete"; - clicked => { - Callabler.delete_selected_items(); - } - } - - select_button := Button { height: parent.height; enabled: !scanning && lists_enabled; @@ -76,6 +67,15 @@ export component ActionButtons inherits HorizontalLayout { } } + delete_button := Button { + height: parent.height; + enabled: !scanning && lists_enabled; + text: "Delete"; + clicked => { + show_remove_popup(); + } + } + Rectangle { horizontal-stretch: 0.5; } diff --git a/krokiet/ui/main_window.slint b/krokiet/ui/main_window.slint index f3f3de3..5debada 100644 --- a/krokiet/ui/main_window.slint +++ b/krokiet/ui/main_window.slint @@ -13,6 +13,7 @@ import {ColorPalette} from "color_palette.slint"; import {GuiState} from "gui_state.slint"; import { Preview } from "preview.slint"; import {PopupNewDirectories} from "popup_new_directories.slint"; +import {PopupDelete} from "popup_delete.slint"; import { PopupSelectResults } from "popup_select_results.slint"; import { ToolSettings } from "tool_settings.slint"; @@ -122,6 +123,9 @@ export component MainWindow inherits Window { select_popup_window.y_offset = y_offset; select_popup_window.show_popup(); } + show_remove_popup => { + delete_popup_window.show_popup(); + } } text_summary := LineEdit { @@ -158,6 +162,13 @@ export component MainWindow inherits Window { width: root.width; } + delete_popup_window := PopupDelete { + height: root.height; + width: root.width; + + x: parent.x + (root.width - self.popup_width) / 2.0; + y: parent.y + (parent.height - self.popup_height) / 2.0; + } scan_ended(scan_text) => { text_summary_text = scan_text; diff --git a/krokiet/ui/popup_delete.slint b/krokiet/ui/popup_delete.slint new file mode 100644 index 0000000..d4988d3 --- /dev/null +++ b/krokiet/ui/popup_delete.slint @@ -0,0 +1,73 @@ +import { Button, VerticalBox ,TextEdit, HorizontalBox, TabWidget, ListView, StandardListView, StandardTableView, CheckBox, LineEdit} from "std-widgets.slint"; +import {SelectableTableView} from "selectable_tree_view.slint"; +import {LeftSidePanel} from "left_side_panel.slint"; +import {MainList} from "main_lists.slint"; +import {CurrentTab, ProgressToSend} from "common.slint"; +import { ActionButtons } from "action_buttons.slint"; +import { Progress } from "progress.slint"; +import {MainListModel, SelectMode, SelectModel} from "common.slint"; +import {Settings} from "settings.slint"; +import {Callabler} from "callabler.slint"; +import { BottomPanel } from "bottom_panel.slint"; +import {ColorPalette} from "color_palette.slint"; +import {GuiState} from "gui_state.slint"; +import { Preview } from "preview.slint"; + +export component PopupDelete inherits Rectangle { + out property popup_width: 350px; + out property popup_height: 150px; + callback show_popup(); + + popup_window := PopupWindow { + width: popup_width; + height: popup_height; + + close-on-click: true; + Rectangle { + width: parent.width; + height: parent.height; + border-radius: 5px; + background: ColorPalette.popup_background; + VerticalLayout { + Text { + vertical-stretch: 0.0; + text: "Delete items"; + vertical-alignment: center; + horizontal-alignment: center; + font-size: 13px; + padding: 10px; + } + Text { + vertical-stretch: 1.0; + text: "Are you sure you want to delete the selected items?"; + vertical-alignment: center; + horizontal-alignment: center; + font-size: 13px; + padding: 10px; + } + HorizontalLayout { + Button { + text: "Yes"; + clicked => { + popup_window.close(); + Callabler.delete_selected_items(); + } + } + Rectangle { + + } + Button { + text: "No"; + clicked => { + popup_window.close(); + } + } + } + } + } + } + + show_popup() => { + popup_window.show(); + } +} \ No newline at end of file