From 8f202dd2efa6ac0119954065a92e26edf1603112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= Date: Sat, 10 Feb 2024 23:31:46 +0100 Subject: [PATCH] Selections --- krokiet/src/common.rs | 20 ++++++- krokiet/src/connect_delete.rs | 16 +----- krokiet/src/connect_select.rs | 82 +++++++++++++++++++++++++++ krokiet/src/main.rs | 3 + krokiet/ui/action_buttons.slint | 1 - krokiet/ui/callabler.slint | 2 + krokiet/ui/common.slint | 5 ++ krokiet/ui/gui_state.slint | 5 +- krokiet/ui/left_side_panel.slint | 3 + krokiet/ui/popup_select_results.slint | 6 +- 10 files changed, 124 insertions(+), 19 deletions(-) diff --git a/krokiet/src/common.rs b/krokiet/src/common.rs index 6d3fcb7..adf777a 100644 --- a/krokiet/src/common.rs +++ b/krokiet/src/common.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel}; +use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel, MainListModel, MainWindow}; use slint::{ModelRc, SharedString, VecModel}; // Remember to match updated this according to ui/main_lists.slint and connect_scan.rs files @@ -28,6 +28,24 @@ pub fn get_is_header_mode(active_tab: CurrentTab) -> bool { } } +pub fn get_tool_model(app: &MainWindow, tab: CurrentTab) -> ModelRc { + match tab { + CurrentTab::EmptyFolders => app.get_empty_folder_model(), + CurrentTab::SimilarImages => app.get_similar_images_model(), + CurrentTab::EmptyFiles => app.get_empty_files_model(), + CurrentTab::Settings => panic!("Button should be disabled"), + } +} + +pub fn set_tool_model(app: &MainWindow, tab: CurrentTab, model: ModelRc) { + match tab { + CurrentTab::EmptyFolders => app.set_empty_folder_model(model), + CurrentTab::SimilarImages => app.set_similar_images_model(model), + CurrentTab::EmptyFiles => app.set_empty_files_model(model), + CurrentTab::Settings => panic!("Button should be disabled"), + } +} + // pub fn create_string_standard_list_view(items: &[String]) -> ModelRc { // let new_folders_standard_list_view = items // .iter() diff --git a/krokiet/src/connect_delete.rs b/krokiet/src/connect_delete.rs index 7b30922..5230a22 100644 --- a/krokiet/src/connect_delete.rs +++ b/krokiet/src/connect_delete.rs @@ -4,7 +4,7 @@ use std::path::MAIN_SEPARATOR; use czkawka_core::common::remove_folder_if_contains_only_empty_folders; -use crate::common::{get_is_header_mode, get_name_idx, get_path_idx}; +use crate::common::{get_is_header_mode, get_name_idx, get_path_idx, get_tool_model, set_tool_model}; use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow}; pub fn connect_delete_button(app: &MainWindow) { @@ -14,22 +14,12 @@ pub fn connect_delete_button(app: &MainWindow) { let active_tab = app.global::().get_active_tab(); - let model = match active_tab { - CurrentTab::EmptyFolders => app.get_empty_folder_model(), - CurrentTab::SimilarImages => app.get_similar_images_model(), - CurrentTab::EmptyFiles => app.get_empty_files_model(), - CurrentTab::Settings => panic!("Button should be disabled"), - }; + let model = get_tool_model(&app, active_tab); let new_model = handle_delete_items(&model, active_tab); if let Some(new_model) = new_model { - match active_tab { - CurrentTab::EmptyFolders => app.set_empty_folder_model(new_model), - CurrentTab::SimilarImages => app.set_similar_images_model(new_model), - CurrentTab::EmptyFiles => app.set_empty_files_model(new_model), - CurrentTab::Settings => panic!("Button should be disabled"), - } + set_tool_model(&app, active_tab, new_model); } app.global::().set_preview_visible(false); diff --git a/krokiet/src/connect_select.rs b/krokiet/src/connect_select.rs index e69de29..7009f13 100644 --- a/krokiet/src/connect_select.rs +++ b/krokiet/src/connect_select.rs @@ -0,0 +1,82 @@ +use crate::common::{get_tool_model, set_tool_model}; +use crate::{Callabler, GuiState, MainListModel, MainWindow, SelectMode}; +use crate::{CurrentTab, SelectModel}; +use slint::{ComponentHandle, Model, ModelRc, VecModel}; + +// TODO optimize this, not sure if it is possible to not copy entire model to just select item +// https://github.com/slint-ui/slint/discussions/4595 +pub fn connect_select(app: &MainWindow) { + let a = app.as_weak(); + app.global::().on_select_items(move |select_mode| { + let app = a.upgrade().unwrap(); + let active_tab = app.global::().get_active_tab(); + let current_model = get_tool_model(&app, active_tab); + + let new_model = match select_mode { + SelectMode::SelectAll => select_all(current_model), + SelectMode::UnselectAll => deselect_all(current_model), + SelectMode::InvertSelection => invert_selection(current_model), + }; + set_tool_model(&app, active_tab, new_model); + }); +} + +pub fn connect_showing_proper_select_buttons(app: &MainWindow) { + set_select_buttons(&app); + let a = app.as_weak(); + app.global::().on_tab_changed(move || { + let app = a.upgrade().unwrap(); + set_select_buttons(&app); + }); +} + +fn set_select_buttons(app: &MainWindow) { + // let active_tab = app.global::().get_active_tab(); + let base_buttons = vec![SelectMode::SelectAll, SelectMode::UnselectAll, SelectMode::InvertSelection]; + + // TODO Here needs to be put logic to set custom buttons depending on tab + + let new_select_model = base_buttons + .into_iter() + .map(|e| SelectModel { + name: translate_select_mode(e).into(), + data: e, + }) + .collect::>(); + + app.global::().set_select_results_list(ModelRc::new(VecModel::from(new_select_model))); +} + +fn translate_select_mode(select_mode: SelectMode) -> String { + match select_mode { + SelectMode::SelectAll => "Select all".into(), + SelectMode::UnselectAll => "Unselect all".into(), + SelectMode::InvertSelection => "Invert selection".into(), + } +} + +fn select_all(model: ModelRc) -> ModelRc { + let mut old_data = model.iter().collect::>(); + old_data.iter_mut().for_each(|x| { + if !x.header_row { + x.checked = true + } + }); + ModelRc::new(VecModel::from(old_data)) +} + +fn deselect_all(model: ModelRc) -> ModelRc { + let mut old_data = model.iter().collect::>(); + old_data.iter_mut().for_each(|x| x.checked = false); + ModelRc::new(VecModel::from(old_data)) +} + +fn invert_selection(model: ModelRc) -> ModelRc { + let mut old_data = model.iter().collect::>(); + old_data.iter_mut().for_each(|x| { + if !x.header_row { + x.checked = !x.checked + } + }); + ModelRc::new(VecModel::from(old_data)) +} diff --git a/krokiet/src/main.rs b/krokiet/src/main.rs index cce150f..f8ca60a 100644 --- a/krokiet/src/main.rs +++ b/krokiet/src/main.rs @@ -30,6 +30,7 @@ use crate::connect_directories_changes::connect_add_remove_directories; use crate::connect_open::connect_open_items; use crate::connect_progress_receiver::connect_progress_gathering; use crate::connect_scan::connect_scan_button; +use crate::connect_select::{connect_select, connect_showing_proper_select_buttons}; use crate::connect_show_preview::connect_show_preview; use crate::connect_stop::connect_stop_button; use crate::connect_translation::connect_translations; @@ -84,6 +85,8 @@ fn main() { connect_show_preview(&app); connect_translations(&app); connect_changing_settings_preset(&app); + connect_select(&app); + connect_showing_proper_select_buttons(&app); app.run().unwrap(); diff --git a/krokiet/ui/action_buttons.slint b/krokiet/ui/action_buttons.slint index 91d6958..5034ae3 100644 --- a/krokiet/ui/action_buttons.slint +++ b/krokiet/ui/action_buttons.slint @@ -5,7 +5,6 @@ import {CurrentTab} from "common.slint"; import {BottomPanelVisibility} from "common.slint"; import {Callabler} from "callabler.slint"; import {GuiState} from "gui_state.slint"; -import { ContextMenu } from "widgets/context_menu.slint"; export component VisibilityButton inherits Button { in-out property button_visibility; diff --git a/krokiet/ui/callabler.slint b/krokiet/ui/callabler.slint index 70a58fb..35437b3 100644 --- a/krokiet/ui/callabler.slint +++ b/krokiet/ui/callabler.slint @@ -20,6 +20,8 @@ export global Callabler { callback load_current_preset(); callback reset_current_preset(); + callback tab_changed(); + // Translations pure callback translate(string, [{key: string, value: string}]) -> string; diff --git a/krokiet/ui/common.slint b/krokiet/ui/common.slint index fac57d5..95f888a 100644 --- a/krokiet/ui/common.slint +++ b/krokiet/ui/common.slint @@ -44,4 +44,9 @@ export enum SelectMode { SelectAll, UnselectAll, InvertSelection +} + +export struct SelectModel { + data: SelectMode, + name: string } \ No newline at end of file diff --git a/krokiet/ui/gui_state.slint b/krokiet/ui/gui_state.slint index 697045d..400ade8 100644 --- a/krokiet/ui/gui_state.slint +++ b/krokiet/ui/gui_state.slint @@ -1,6 +1,8 @@ import {CurrentTab} from "common.slint"; +import {SelectModel, SelectMode} from "common.slint"; -// State to show +// State Gui state that shows the current state of the GUI +// It extends Settings global state with settings that are not saved to the settings file export global GuiState { in-out property app_width; in-out property app_height; @@ -17,4 +19,5 @@ export global GuiState { in-out property available_subsettings: active_tab == CurrentTab.SimilarImages; in-out property active_tab: CurrentTab.EmptyFiles; + in-out property <[SelectModel]> select_results_list: [{data: SelectMode.SelectAll, name: "Select All"}, {data: SelectMode.UnselectAll, name: "Deselect All"}]; } diff --git a/krokiet/ui/left_side_panel.slint b/krokiet/ui/left_side_panel.slint index 9e92d2b..8d8e349 100644 --- a/krokiet/ui/left_side_panel.slint +++ b/krokiet/ui/left_side_panel.slint @@ -2,6 +2,7 @@ import { Button, VerticalBox , HorizontalBox, TabWidget, ListView, StandardListV import {CurrentTab} from "common.slint"; import {ColorPalette} from "color_palette.slint"; import {GuiState} from "gui_state.slint"; +import {Callabler} from "callabler.slint"; component TabItem { in property scanning; @@ -19,6 +20,7 @@ component TabItem { return; } GuiState.active_tab = root.curr-tab; + Callabler.tab_changed(); changed_current_tab(); } } @@ -130,6 +132,7 @@ export component LeftSidePanel { icon: @image-url("../icons/settings.svg"); clicked => { GuiState.active_tab = CurrentTab.Settings; + Callabler.tab_changed(); root.changed_current_tab(); } } diff --git a/krokiet/ui/popup_select_results.slint b/krokiet/ui/popup_select_results.slint index 8c8e91d..0d02844 100644 --- a/krokiet/ui/popup_select_results.slint +++ b/krokiet/ui/popup_select_results.slint @@ -5,7 +5,7 @@ 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} from "common.slint"; +import {MainListModel, SelectMode, SelectModel} from "common.slint"; import {Settings} from "settings.slint"; import {Callabler} from "callabler.slint"; import { BottomPanel } from "bottom_panel.slint"; @@ -15,7 +15,7 @@ import { Preview } from "preview.slint"; export component PopupSelectResults inherits Rectangle { callback show_popup(); - property <[{data: string, name: string}]> model: [{data: "SELECT_ALL", name: "Select All"}, {data: "DESELECT_ALL", name: "Deselect All"}, {data: "INVERT_SELECTION", name: "Invert Selection"}]; + property <[SelectModel]> model: GuiState.select_results_list; property item_height: 30px; property item_width: 140px; out property all_items_height: item_height * model.length; @@ -38,7 +38,7 @@ export component PopupSelectResults inherits Rectangle { width: item_width; clicked => { - debug(i.data); + Callabler.select_items(i.data); popup_window.close(); } }