Selections
This commit is contained in:
parent
305af6a391
commit
8f202dd2ef
|
@ -1,6 +1,6 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel};
|
use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel, MainListModel, MainWindow};
|
||||||
use slint::{ModelRc, SharedString, VecModel};
|
use slint::{ModelRc, SharedString, VecModel};
|
||||||
|
|
||||||
// Remember to match updated this according to ui/main_lists.slint and connect_scan.rs files
|
// 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<MainListModel> {
|
||||||
|
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<MainListModel>) {
|
||||||
|
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<StandardListViewItem> {
|
// pub fn create_string_standard_list_view(items: &[String]) -> ModelRc<StandardListViewItem> {
|
||||||
// let new_folders_standard_list_view = items
|
// let new_folders_standard_list_view = items
|
||||||
// .iter()
|
// .iter()
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::path::MAIN_SEPARATOR;
|
||||||
|
|
||||||
use czkawka_core::common::remove_folder_if_contains_only_empty_folders;
|
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};
|
use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow};
|
||||||
|
|
||||||
pub fn connect_delete_button(app: &MainWindow) {
|
pub fn connect_delete_button(app: &MainWindow) {
|
||||||
|
@ -14,22 +14,12 @@ pub fn connect_delete_button(app: &MainWindow) {
|
||||||
|
|
||||||
let active_tab = app.global::<GuiState>().get_active_tab();
|
let active_tab = app.global::<GuiState>().get_active_tab();
|
||||||
|
|
||||||
let model = match active_tab {
|
let model = get_tool_model(&app, 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 new_model = handle_delete_items(&model, active_tab);
|
let new_model = handle_delete_items(&model, active_tab);
|
||||||
|
|
||||||
if let Some(new_model) = new_model {
|
if let Some(new_model) = new_model {
|
||||||
match active_tab {
|
set_tool_model(&app, active_tab, new_model);
|
||||||
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"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.global::<GuiState>().set_preview_visible(false);
|
app.global::<GuiState>().set_preview_visible(false);
|
||||||
|
|
|
@ -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::<Callabler>().on_select_items(move |select_mode| {
|
||||||
|
let app = a.upgrade().unwrap();
|
||||||
|
let active_tab = app.global::<GuiState>().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::<Callabler>().on_tab_changed(move || {
|
||||||
|
let app = a.upgrade().unwrap();
|
||||||
|
set_select_buttons(&app);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_select_buttons(app: &MainWindow) {
|
||||||
|
// let active_tab = app.global::<GuiState>().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::<Vec<_>>();
|
||||||
|
|
||||||
|
app.global::<GuiState>().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<MainListModel>) -> ModelRc<MainListModel> {
|
||||||
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
|
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<MainListModel>) -> ModelRc<MainListModel> {
|
||||||
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
|
old_data.iter_mut().for_each(|x| x.checked = false);
|
||||||
|
ModelRc::new(VecModel::from(old_data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invert_selection(model: ModelRc<MainListModel>) -> ModelRc<MainListModel> {
|
||||||
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
|
old_data.iter_mut().for_each(|x| {
|
||||||
|
if !x.header_row {
|
||||||
|
x.checked = !x.checked
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ModelRc::new(VecModel::from(old_data))
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ use crate::connect_directories_changes::connect_add_remove_directories;
|
||||||
use crate::connect_open::connect_open_items;
|
use crate::connect_open::connect_open_items;
|
||||||
use crate::connect_progress_receiver::connect_progress_gathering;
|
use crate::connect_progress_receiver::connect_progress_gathering;
|
||||||
use crate::connect_scan::connect_scan_button;
|
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_show_preview::connect_show_preview;
|
||||||
use crate::connect_stop::connect_stop_button;
|
use crate::connect_stop::connect_stop_button;
|
||||||
use crate::connect_translation::connect_translations;
|
use crate::connect_translation::connect_translations;
|
||||||
|
@ -84,6 +85,8 @@ fn main() {
|
||||||
connect_show_preview(&app);
|
connect_show_preview(&app);
|
||||||
connect_translations(&app);
|
connect_translations(&app);
|
||||||
connect_changing_settings_preset(&app);
|
connect_changing_settings_preset(&app);
|
||||||
|
connect_select(&app);
|
||||||
|
connect_showing_proper_select_buttons(&app);
|
||||||
|
|
||||||
app.run().unwrap();
|
app.run().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {CurrentTab} from "common.slint";
|
||||||
import {BottomPanelVisibility} from "common.slint";
|
import {BottomPanelVisibility} from "common.slint";
|
||||||
import {Callabler} from "callabler.slint";
|
import {Callabler} from "callabler.slint";
|
||||||
import {GuiState} from "gui_state.slint";
|
import {GuiState} from "gui_state.slint";
|
||||||
import { ContextMenu } from "widgets/context_menu.slint";
|
|
||||||
|
|
||||||
export component VisibilityButton inherits Button {
|
export component VisibilityButton inherits Button {
|
||||||
in-out property <BottomPanelVisibility> button_visibility;
|
in-out property <BottomPanelVisibility> button_visibility;
|
||||||
|
|
|
@ -20,6 +20,8 @@ export global Callabler {
|
||||||
callback load_current_preset();
|
callback load_current_preset();
|
||||||
callback reset_current_preset();
|
callback reset_current_preset();
|
||||||
|
|
||||||
|
callback tab_changed();
|
||||||
|
|
||||||
// Translations
|
// Translations
|
||||||
pure callback translate(string, [{key: string, value: string}]) -> string;
|
pure callback translate(string, [{key: string, value: string}]) -> string;
|
||||||
|
|
||||||
|
|
|
@ -44,4 +44,9 @@ export enum SelectMode {
|
||||||
SelectAll,
|
SelectAll,
|
||||||
UnselectAll,
|
UnselectAll,
|
||||||
InvertSelection
|
InvertSelection
|
||||||
|
}
|
||||||
|
|
||||||
|
export struct SelectModel {
|
||||||
|
data: SelectMode,
|
||||||
|
name: string
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
import {CurrentTab} from "common.slint";
|
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 {
|
export global GuiState {
|
||||||
in-out property <length> app_width;
|
in-out property <length> app_width;
|
||||||
in-out property <length> app_height;
|
in-out property <length> app_height;
|
||||||
|
@ -17,4 +19,5 @@ export global GuiState {
|
||||||
|
|
||||||
in-out property <bool> available_subsettings: active_tab == CurrentTab.SimilarImages;
|
in-out property <bool> available_subsettings: active_tab == CurrentTab.SimilarImages;
|
||||||
in-out property <CurrentTab> active_tab: CurrentTab.EmptyFiles;
|
in-out property <CurrentTab> active_tab: CurrentTab.EmptyFiles;
|
||||||
|
in-out property <[SelectModel]> select_results_list: [{data: SelectMode.SelectAll, name: "Select All"}, {data: SelectMode.UnselectAll, name: "Deselect All"}];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Button, VerticalBox , HorizontalBox, TabWidget, ListView, StandardListV
|
||||||
import {CurrentTab} from "common.slint";
|
import {CurrentTab} from "common.slint";
|
||||||
import {ColorPalette} from "color_palette.slint";
|
import {ColorPalette} from "color_palette.slint";
|
||||||
import {GuiState} from "gui_state.slint";
|
import {GuiState} from "gui_state.slint";
|
||||||
|
import {Callabler} from "callabler.slint";
|
||||||
|
|
||||||
component TabItem {
|
component TabItem {
|
||||||
in property <bool> scanning;
|
in property <bool> scanning;
|
||||||
|
@ -19,6 +20,7 @@ component TabItem {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GuiState.active_tab = root.curr-tab;
|
GuiState.active_tab = root.curr-tab;
|
||||||
|
Callabler.tab_changed();
|
||||||
changed_current_tab();
|
changed_current_tab();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,6 +132,7 @@ export component LeftSidePanel {
|
||||||
icon: @image-url("../icons/settings.svg");
|
icon: @image-url("../icons/settings.svg");
|
||||||
clicked => {
|
clicked => {
|
||||||
GuiState.active_tab = CurrentTab.Settings;
|
GuiState.active_tab = CurrentTab.Settings;
|
||||||
|
Callabler.tab_changed();
|
||||||
root.changed_current_tab();
|
root.changed_current_tab();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {MainList} from "main_lists.slint";
|
||||||
import {CurrentTab, ProgressToSend} from "common.slint";
|
import {CurrentTab, ProgressToSend} from "common.slint";
|
||||||
import { ActionButtons } from "action_buttons.slint";
|
import { ActionButtons } from "action_buttons.slint";
|
||||||
import { Progress } from "progress.slint";
|
import { Progress } from "progress.slint";
|
||||||
import {MainListModel} from "common.slint";
|
import {MainListModel, SelectMode, SelectModel} from "common.slint";
|
||||||
import {Settings} from "settings.slint";
|
import {Settings} from "settings.slint";
|
||||||
import {Callabler} from "callabler.slint";
|
import {Callabler} from "callabler.slint";
|
||||||
import { BottomPanel } from "bottom_panel.slint";
|
import { BottomPanel } from "bottom_panel.slint";
|
||||||
|
@ -15,7 +15,7 @@ import { Preview } from "preview.slint";
|
||||||
|
|
||||||
export component PopupSelectResults inherits Rectangle {
|
export component PopupSelectResults inherits Rectangle {
|
||||||
callback show_popup();
|
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 <length> item_height: 30px;
|
property <length> item_height: 30px;
|
||||||
property <length> item_width: 140px;
|
property <length> item_width: 140px;
|
||||||
out property <length> all_items_height: item_height * model.length;
|
out property <length> all_items_height: item_height * model.length;
|
||||||
|
@ -38,7 +38,7 @@ export component PopupSelectResults inherits Rectangle {
|
||||||
width: item_width;
|
width: item_width;
|
||||||
|
|
||||||
clicked => {
|
clicked => {
|
||||||
debug(i.data);
|
Callabler.select_items(i.data);
|
||||||
popup_window.close();
|
popup_window.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue