Added popup delete
This commit is contained in:
parent
dfb89b2f5e
commit
04dba35c33
|
@ -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 {
|
match active_tab {
|
||||||
CurrentTab::SimilarImages => 4,
|
CurrentTab::SimilarImages => 4,
|
||||||
CurrentTab::Settings => panic!("Button should be disabled"),
|
CurrentTab::Settings => panic!("Button should be disabled"),
|
||||||
_ => panic!("Unable to get height from this tab"),
|
_ => 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 {
|
match active_tab {
|
||||||
CurrentTab::SimilarImages => 5,
|
CurrentTab::SimilarImages => 5,
|
||||||
CurrentTab::Settings => panic!("Button should be disabled"),
|
CurrentTab::Settings => panic!("Button should be disabled"),
|
||||||
|
|
|
@ -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::{Callabler, GuiState, MainListModel, MainWindow, SelectMode};
|
||||||
use crate::{CurrentTab, SelectModel};
|
use crate::{CurrentTab, SelectModel};
|
||||||
use slint::{ComponentHandle, Model, ModelRc, VecModel};
|
use slint::{ComponentHandle, Model, ModelRc, VecModel};
|
||||||
|
@ -16,9 +18,12 @@ pub fn connect_select(app: &MainWindow) {
|
||||||
SelectMode::SelectAll => select_all(current_model),
|
SelectMode::SelectAll => select_all(current_model),
|
||||||
SelectMode::UnselectAll => deselect_all(current_model),
|
SelectMode::UnselectAll => deselect_all(current_model),
|
||||||
SelectMode::InvertSelection => invert_selection(current_model),
|
SelectMode::InvertSelection => invert_selection(current_model),
|
||||||
SelectMode::SelectTheBiggestSize => select_the_biggest_size(current_model, active_tab),
|
SelectMode::SelectTheBiggestSize => select_by_size_date(current_model, active_tab, true, true),
|
||||||
SelectMode::SelectTheSmallestSize => select_the_small_size(current_model, active_tab),
|
SelectMode::SelectTheSmallestSize => select_by_size_date(current_model, active_tab, false, true),
|
||||||
_ => unimplemented!(),
|
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);
|
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<MainListModel>, active_tab: CurrentTab) -> ModelRc<MainListModel> {
|
// 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<MainListModel>, active_tab: CurrentTab, biggest: bool) -> ModelRc<MainListModel> {
|
||||||
let is_header_mode = get_is_header_mode(active_tab);
|
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::<Vec<_>>();
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
let headers_idx = find_header_idx_and_deselect_all(&mut old_data);
|
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) {
|
if biggest {
|
||||||
let mut max_size = 0;
|
for i in 0..(headers_idx.len() - 1) {
|
||||||
let mut max_size_idx = 0;
|
let mut max_item = 0;
|
||||||
for j in (headers_idx[i] + 1)..headers_idx[i + 1] {
|
let mut max_item_idx = 0;
|
||||||
let int_data = old_data[j].val_int.iter().collect::<Vec<_>>();
|
#[allow(clippy::needless_range_loop)]
|
||||||
let size = connect_i32_into_u64(int_data[size_idx], int_data[size_idx + 1]);
|
for j in (headers_idx[i] + 1)..headers_idx[i + 1] {
|
||||||
if size > max_size {
|
let int_data = old_data[j].val_int.iter().collect::<Vec<_>>();
|
||||||
max_size = size;
|
let item = int_data[width_idx] * int_data[height_idx];
|
||||||
max_size_idx = j;
|
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::<Vec<_>>();
|
||||||
|
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))
|
ModelRc::new(VecModel::from(old_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_the_small_size(model: ModelRc<MainListModel>, active_tab: CurrentTab) -> ModelRc<MainListModel> {
|
fn select_by_size_date(model: ModelRc<MainListModel>, active_tab: CurrentTab, biggest_newest: bool, size: bool) -> ModelRc<MainListModel> {
|
||||||
let is_header_mode = get_is_header_mode(active_tab);
|
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::<Vec<_>>();
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
let headers_idx = find_header_idx_and_deselect_all(&mut old_data);
|
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) {
|
if biggest_newest {
|
||||||
let mut min_size = u64::MAX;
|
for i in 0..(headers_idx.len() - 1) {
|
||||||
let mut min_size_idx = 0;
|
let mut max_item = 0;
|
||||||
for j in (headers_idx[i] + 1)..headers_idx[i + 1] {
|
let mut max_item_idx = 0;
|
||||||
let int_data = old_data[j].val_int.iter().collect::<Vec<_>>();
|
#[allow(clippy::needless_range_loop)]
|
||||||
let size = connect_i32_into_u64(int_data[size_idx], int_data[size_idx + 1]);
|
for j in (headers_idx[i] + 1)..headers_idx[i + 1] {
|
||||||
if size < min_size {
|
let int_data = old_data[j].val_int.iter().collect::<Vec<_>>();
|
||||||
min_size = size;
|
let item = connect_i32_into_u64(int_data[item_idx], int_data[item_idx + 1]);
|
||||||
min_size_idx = j;
|
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::<Vec<_>>();
|
||||||
|
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))
|
ModelRc::new(VecModel::from(old_data))
|
||||||
|
@ -129,11 +176,11 @@ fn select_the_small_size(model: ModelRc<MainListModel>, active_tab: CurrentTab)
|
||||||
|
|
||||||
fn select_all(model: ModelRc<MainListModel>) -> ModelRc<MainListModel> {
|
fn select_all(model: ModelRc<MainListModel>) -> ModelRc<MainListModel> {
|
||||||
let mut old_data = model.iter().collect::<Vec<_>>();
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
old_data.iter_mut().for_each(|x| {
|
for x in &mut old_data {
|
||||||
if !x.header_row {
|
if !x.header_row {
|
||||||
x.checked = true
|
x.checked = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
ModelRc::new(VecModel::from(old_data))
|
ModelRc::new(VecModel::from(old_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,15 +192,15 @@ fn deselect_all(model: ModelRc<MainListModel>) -> ModelRc<MainListModel> {
|
||||||
|
|
||||||
fn invert_selection(model: ModelRc<MainListModel>) -> ModelRc<MainListModel> {
|
fn invert_selection(model: ModelRc<MainListModel>) -> ModelRc<MainListModel> {
|
||||||
let mut old_data = model.iter().collect::<Vec<_>>();
|
let mut old_data = model.iter().collect::<Vec<_>>();
|
||||||
old_data.iter_mut().for_each(|x| {
|
for x in &mut old_data {
|
||||||
if !x.header_row {
|
if !x.header_row {
|
||||||
x.checked = !x.checked
|
x.checked = !x.checked;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
ModelRc::new(VecModel::from(old_data))
|
ModelRc::new(VecModel::from(old_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_header_idx_and_deselect_all(old_data: &mut Vec<MainListModel>) -> Vec<usize> {
|
fn find_header_idx_and_deselect_all(old_data: &mut [MainListModel]) -> Vec<usize> {
|
||||||
let mut header_idx = old_data
|
let mut header_idx = old_data
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -161,55 +208,10 @@ fn find_header_idx_and_deselect_all(old_data: &mut Vec<MainListModel>) -> Vec<us
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
header_idx.push(old_data.len());
|
header_idx.push(old_data.len());
|
||||||
|
|
||||||
old_data.iter_mut().for_each(|x| {
|
for x in old_data.iter_mut() {
|
||||||
if !x.header_row {
|
if !x.header_row {
|
||||||
x.checked = false;
|
x.checked = false;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
header_idx
|
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::<Vec<_>>();
|
|
||||||
// assert_eq!(new_data[0].checked, true);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn prepare_simple_model() -> ModelRc<MainListModel> {
|
|
||||||
// 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,
|
|
||||||
// },
|
|
||||||
// ]))
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ export component ActionButtons inherits HorizontalLayout {
|
||||||
callback scan_stopping;
|
callback scan_stopping;
|
||||||
callback scan_starting(CurrentTab);
|
callback scan_starting(CurrentTab);
|
||||||
callback show_select_popup(length, length);
|
callback show_select_popup(length, length);
|
||||||
|
callback show_remove_popup();
|
||||||
in-out property <BottomPanelVisibility> bottom_panel_visibility: BottomPanelVisibility.Directories;
|
in-out property <BottomPanelVisibility> bottom_panel_visibility: BottomPanelVisibility.Directories;
|
||||||
in-out property <bool> stop_requested: false;
|
in-out property <bool> stop_requested: false;
|
||||||
in-out property <bool> scanning;
|
in-out property <bool> scanning;
|
||||||
|
@ -57,16 +58,6 @@ export component ActionButtons inherits HorizontalLayout {
|
||||||
horizontal-stretch: 0.5;
|
horizontal-stretch: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_button := Button {
|
|
||||||
height: parent.height;
|
|
||||||
enabled: !scanning && lists_enabled;
|
|
||||||
text: "Delete";
|
|
||||||
clicked => {
|
|
||||||
Callabler.delete_selected_items();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
select_button := Button {
|
select_button := Button {
|
||||||
height: parent.height;
|
height: parent.height;
|
||||||
enabled: !scanning && lists_enabled;
|
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 {
|
Rectangle {
|
||||||
horizontal-stretch: 0.5;
|
horizontal-stretch: 0.5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {ColorPalette} from "color_palette.slint";
|
||||||
import {GuiState} from "gui_state.slint";
|
import {GuiState} from "gui_state.slint";
|
||||||
import { Preview } from "preview.slint";
|
import { Preview } from "preview.slint";
|
||||||
import {PopupNewDirectories} from "popup_new_directories.slint";
|
import {PopupNewDirectories} from "popup_new_directories.slint";
|
||||||
|
import {PopupDelete} from "popup_delete.slint";
|
||||||
import { PopupSelectResults } from "popup_select_results.slint";
|
import { PopupSelectResults } from "popup_select_results.slint";
|
||||||
import { ToolSettings } from "tool_settings.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.y_offset = y_offset;
|
||||||
select_popup_window.show_popup();
|
select_popup_window.show_popup();
|
||||||
}
|
}
|
||||||
|
show_remove_popup => {
|
||||||
|
delete_popup_window.show_popup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text_summary := LineEdit {
|
text_summary := LineEdit {
|
||||||
|
@ -158,6 +162,13 @@ export component MainWindow inherits Window {
|
||||||
width: root.width;
|
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) => {
|
scan_ended(scan_text) => {
|
||||||
text_summary_text = scan_text;
|
text_summary_text = scan_text;
|
||||||
|
|
73
krokiet/ui/popup_delete.slint
Normal file
73
krokiet/ui/popup_delete.slint
Normal file
|
@ -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 <length> popup_width: 350px;
|
||||||
|
out property <length> 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue