Proper handling of select by shift

This commit is contained in:
Jeremy Soller 2024-02-29 15:21:59 -07:00
parent a1558b20c6
commit f0956f494a
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
2 changed files with 93 additions and 94 deletions

View file

@ -447,7 +447,7 @@ impl Application for App {
}
Message::Filename(new_filename) => {
// Select based on filename
self.tab.select_by_name(&new_filename);
self.tab.select_name(&new_filename);
if let DialogKind::SaveFile { filename } = &mut self.flags.kind {
*filename = new_filename;

View file

@ -562,6 +562,8 @@ pub struct Tab {
pub history: Vec<Location>,
pub config: TabConfig,
items_opt: Option<Vec<Item>>,
select_focus: Option<usize>,
select_shift: Option<usize>,
sort_name: HeadingOptions,
sort_direction: bool,
}
@ -584,6 +586,8 @@ impl Tab {
history,
config,
items_opt: None,
select_focus: None,
select_shift: None,
sort_name,
sort_direction,
}
@ -607,9 +611,11 @@ impl Tab {
pub fn set_items(&mut self, items: Vec<Item>) {
self.items_opt = Some(items);
self.select_focus = None;
}
pub fn select_all(&mut self) {
self.select_focus = None;
if let Some(ref mut items) = self.items_opt {
for item in items.iter_mut() {
if !self.config.show_hidden && item.hidden {
@ -623,6 +629,7 @@ impl Tab {
}
pub fn select_none(&mut self) -> bool {
self.select_focus = None;
let mut had_selection = false;
if let Some(ref mut items) = self.items_opt {
for item in items.iter_mut() {
@ -635,102 +642,92 @@ impl Tab {
had_selection
}
pub fn select_by_drag(&mut self, rect: Rectangle) {
let items = match &mut self.items_opt {
Some(some) => some,
None => return,
};
for (_i, item) in items.iter_mut().enumerate() {
//TODO: modifiers
item.selected = match item.rect_opt.get() {
Some(item_rect) => item_rect.intersects(&rect),
None => false,
};
}
}
pub fn select_by_name(&mut self, name: &str) {
pub fn select_name(&mut self, name: &str) {
self.select_focus = None;
if let Some(ref mut items) = self.items_opt {
for item in items.iter_mut() {
item.selected = item.name == name;
}
}
}
fn selection_first(&self) -> Option<(usize, usize)> {
let items = self.items_opt.as_ref()?;
let mut first = None;
for item in items.iter() {
if !item.selected {
continue;
}
let (row, col) = match item.pos_opt.get() {
Some(some) => some,
None => continue,
};
first = Some(match first {
Some((first_row, first_col)) => {
if row < first_row {
(row, col)
} else if row == first_row {
(row, col.min(first_row))
} else {
(first_row, first_col)
}
}
None => (row, col),
});
}
first
}
fn selection_last(&self) -> Option<(usize, usize)> {
let items = self.items_opt.as_ref()?;
let mut last = None;
for item in items.iter() {
if !item.selected {
continue;
}
let (row, col) = match item.pos_opt.get() {
Some(some) => some,
None => continue,
};
last = Some(match last {
Some((last_row, last_col)) => {
if row > last_row {
(row, col)
} else if row == last_row {
(row, col.max(last_row))
} else {
(last_row, last_col)
}
}
None => (row, col),
});
}
last
}
fn select_position(&mut self, row: usize, col: usize, mod_shift: bool) -> bool {
let mut found = false;
if let Some(ref mut items) = self.items_opt {
for item in items.iter_mut() {
if item.pos_opt.get() == Some((row, col)) {
for (i, item) in items.iter_mut().enumerate() {
if item.name == name {
self.select_focus = Some(i);
item.selected = true;
found = true;
} else if !mod_shift {
} else {
item.selected = false;
}
}
}
}
fn select_position(&mut self, row: usize, col: usize, mod_shift: bool) -> bool {
let mut start = (row, col);
let mut end = (row, col);
if mod_shift {
if self.select_focus.is_none() || self.select_shift.is_none() {
// Set select shift to initial state if necessary
self.select_shift = self.select_focus;
}
if let Some(pos) = self.select_shift_pos_opt() {
if pos.0 < row || (pos.0 == row && pos.1 < col) {
start = pos;
} else {
end = pos;
}
}
} else {
// Clear select shift if the modifier is not set
self.select_shift = None;
};
let mut found = false;
if let Some(ref mut items) = self.items_opt {
for (i, item) in items.iter_mut().enumerate() {
item.selected = false;
let pos = match item.pos_opt.get() {
Some(some) => some,
None => continue,
};
if pos.0 < start.0 || (pos.0 == start.0 && pos.1 < start.1) {
// Before start
continue;
}
if pos.0 > end.0 || (pos.0 == end.0 && pos.1 > end.1) {
// After end
continue;
}
if pos == (row, col) {
// Update focus if this is what we wanted to select
self.select_focus = Some(i);
}
item.selected = true;
found = true;
}
}
found
}
pub fn select_rect(&mut self, rect: Rectangle) {
self.select_focus = None;
if let Some(ref mut items) = self.items_opt {
for (_i, item) in items.iter_mut().enumerate() {
//TODO: modifiers
item.selected = match item.rect_opt.get() {
Some(item_rect) => item_rect.intersects(&rect),
None => false,
};
}
}
}
fn select_focus_pos_opt(&self) -> Option<(usize, usize)> {
let items = self.items_opt.as_ref()?;
let item = items.get(self.select_focus?)?;
item.pos_opt.get()
}
fn select_shift_pos_opt(&self) -> Option<(usize, usize)> {
let items = self.items_opt.as_ref()?;
let item = items.get(self.select_shift?)?;
item.pos_opt.get()
}
pub fn update(&mut self, message: Message, modifiers: Modifiers) -> Vec<Command> {
let mut commands = Vec::new();
let mut cd = None;
@ -741,6 +738,7 @@ impl Tab {
&& self.dialog.as_ref().map_or(true, |x| x.multiple());
match message {
Message::Click(click_i_opt) => {
self.select_focus = None;
if let Some(ref mut items) = self.items_opt {
for (i, item) in items.iter_mut().enumerate() {
if Some(i) == click_i_opt {
@ -756,7 +754,7 @@ impl Tab {
}
}
}
self.select_focus = Some(i);
item.selected = true;
if let Some(click_time) = item.click_time {
if click_time.elapsed() < DOUBLE_CLICK_DURATION {
@ -802,7 +800,7 @@ impl Tab {
}
Message::Drag(rect_opt) => match rect_opt {
Some(rect) => {
self.select_by_drag(rect);
self.select_rect(rect);
}
None => {}
},
@ -829,7 +827,7 @@ impl Tab {
}
}
Message::ItemDown => {
if let Some((row, col)) = self.selection_last() {
if let Some((row, col)) = self.select_focus_pos_opt() {
//TODO: Shift modifier should select items in between
// Try to select item in next row
if !self.select_position(row + 1, col, mod_shift) {
@ -842,7 +840,7 @@ impl Tab {
}
}
Message::ItemLeft => {
if let Some((row, col)) = self.selection_first() {
if let Some((row, col)) = self.select_focus_pos_opt() {
// Try to select previous item in current row
if !col
.checked_sub(1)
@ -873,7 +871,7 @@ impl Tab {
}
}
Message::ItemRight => {
if let Some((row, col)) = self.selection_last() {
if let Some((row, col)) = self.select_focus_pos_opt() {
// Try to select next item in current row
if !self.select_position(row, col + 1, mod_shift) {
// Try to select first item in next row
@ -888,7 +886,7 @@ impl Tab {
}
}
Message::ItemUp => {
if let Some((row, col)) = self.selection_first() {
if let Some((row, col)) = self.select_focus_pos_opt() {
//TODO: Shift modifier should select items in between
// Try to select item in last row
if !row
@ -998,6 +996,7 @@ impl Tab {
if location != self.location {
self.location = location.clone();
self.items_opt = None;
self.select_focus = None;
self.edit_location = None;
if let Some(history_i) = history_i_opt {
// Navigating in history