summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-09-11 12:50:06 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-09-11 17:02:27 +0300
commited27ed604ce8e4ec280e34bb7a2dce42926089b0 (patch)
tree5e8b1680012c4714be09dec4d33d71fa109cb8f5 /src
parent9e20f6556a8d7b788e27ba670546e9012d94e0a6 (diff)
listing: select multiple messages with a motion
- Press a number (movement multiplier) - Press "select_entry" shortcut (default: v) - Press a movement (arrow keys, PageUp/Down, Home/End) - Resulting selection will be symmetric difference of previous selection plus all the entries traversed with movement
Diffstat (limited to 'src')
-rw-r--r--src/components/mail/listing.rs21
-rw-r--r--src/components/mail/listing/compact.rs86
-rw-r--r--src/components/mail/listing/conversations.rs83
3 files changed, 179 insertions, 11 deletions
diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs
index d3fe1b03..e5dbce68 100644
--- a/src/components/mail/listing.rs
+++ b/src/components/mail/listing.rs
@@ -376,6 +376,7 @@ pub trait ListingTrait: Component {
_context: &Context,
) {
}
+ fn set_command_modifier(&mut self, _is_active: bool) {}
fn set_movement(&mut self, mvm: PageMovement);
}
@@ -647,12 +648,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -698,12 +701,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -797,12 +802,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -818,12 +825,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -839,12 +848,14 @@ impl Component for Listing {
1
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
mult
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -860,12 +871,14 @@ impl Component for Listing {
1
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
mult
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -957,12 +970,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -1009,12 +1024,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -1063,12 +1080,14 @@ impl Component for Listing {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -1131,6 +1150,7 @@ impl Component for Listing {
}
UIEvent::Input(Key::Esc) | UIEvent::Input(Key::Alt('')) if !self.cmd_buf.is_empty() => {
self.cmd_buf.clear();
+ self.component.set_command_modifier(false);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@@ -1138,6 +1158,7 @@ impl Component for Listing {
}
UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
self.cmd_buf.push(c);
+ self.component.set_command_modifier(true);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufSet(
diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs
index b558c10b..5f140184 100644
--- a/src/components/mail/listing/compact.rs
+++ b/src/components/mail/listing/compact.rs
@@ -160,6 +160,8 @@ pub struct CompactListing {
color_cache: ColorCache,
movement: Option<PageMovement>,
+ modifier_active: bool,
+ modifier_command: Option<char>,
id: ComponentId,
}
@@ -858,6 +860,10 @@ impl ListingTrait for CompactListing {
}
}
+ fn set_command_modifier(&mut self, is_active: bool) {
+ self.modifier_active = is_active;
+ }
+
fn set_movement(&mut self, mvm: PageMovement) {
self.movement = Some(mvm);
self.set_dirty(true);
@@ -897,6 +903,8 @@ impl CompactListing {
view: ThreadView::default(),
color_cache: ColorCache::default(),
movement: None,
+ modifier_active: false,
+ modifier_command: None,
id: ComponentId::new_v4(),
}
}
@@ -1395,18 +1403,79 @@ impl Component for CompactListing {
area = (set_y(upper_left, y + 1), bottom_right);
}
+ let (upper_left, bottom_right) = area;
+ let rows = get_y(bottom_right) - get_y(upper_left) + 1;
+
+ if let Some('s') = self.modifier_command.take() {
+ self.set_command_modifier(false);
+ if let Some(mvm) = self.movement.as_ref() {
+ match mvm {
+ PageMovement::Up(amount) => {
+ for c in self.new_cursor_pos.2.saturating_sub(*amount)
+ ..=self.new_cursor_pos.2
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::PageUp(multiplier) => {
+ for c in self.new_cursor_pos.2.saturating_sub(rows * multiplier)
+ ..=self.new_cursor_pos.2
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::Down(amount) => {
+ for c in self.new_cursor_pos.2
+ ..std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1)
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::PageDown(multiplier) => {
+ for c in self.new_cursor_pos.2
+ ..std::cmp::min(
+ self.new_cursor_pos.2 + rows * multiplier + 1,
+ self.length,
+ )
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::Right(_) | PageMovement::Left(_) => {}
+ PageMovement::Home => {
+ for c in 0..=self.new_cursor_pos.2 {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::End => {
+ for c in self.new_cursor_pos.2..self.length {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ }
+ }
+ }
if !self.row_updates.is_empty() {
- let (upper_left, bottom_right) = area;
while let Some(row) = self.row_updates.pop() {
self.update_line(context, row);
let row: usize = self.order[&row];
-
- let rows = get_y(bottom_right) - get_y(upper_left) + 1;
let page_no = (self.new_cursor_pos.2).wrapping_div(rows);
let top_idx = page_no * rows;
- if row >= top_idx && row <= top_idx + rows {
+ if row >= top_idx && row < top_idx + rows {
let area = (
set_y(upper_left, get_y(upper_left) + (row % rows)),
set_y(bottom_right, get_y(upper_left) + (row % rows)),
@@ -1475,8 +1544,13 @@ impl Component for CompactListing {
key == shortcuts[CompactListing::DESCRIPTION]["select_entry"]
) =>
{
- let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2);
- self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
+ if self.modifier_active {
+ self.modifier_command = Some('s');
+ } else {
+ let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2);
+ self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
+ }
+ return true;
}
UIEvent::Action(ref action) => {
match action {
diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs
index 68dd678a..44603ae0 100644
--- a/src/components/mail/listing/conversations.rs
+++ b/src/components/mail/listing/conversations.rs
@@ -123,6 +123,8 @@ pub struct ConversationsListing {
color_cache: ColorCache,
movement: Option<PageMovement>,
+ modifier_active: bool,
+ modifier_command: Option<char>,
id: ComponentId,
}
@@ -848,6 +850,10 @@ impl ListingTrait for ConversationsListing {
}
}
+ fn set_command_modifier(&mut self, is_active: bool) {
+ self.modifier_active = is_active;
+ }
+
fn set_movement(&mut self, mvm: PageMovement) {
self.movement = Some(mvm);
self.set_dirty(true);
@@ -884,6 +890,8 @@ impl ConversationsListing {
view: ThreadView::default(),
color_cache: ColorCache::default(),
movement: None,
+ modifier_active: false,
+ modifier_command: None,
id: ComponentId::new_v4(),
}
}
@@ -1201,20 +1209,81 @@ impl Component for ConversationsListing {
area = (set_y(upper_left, y + 1), bottom_right);
}
+ let (upper_left, bottom_right) = area;
+ let rows = (get_y(bottom_right) - get_y(upper_left) + 1) / 3;
+ if let Some('s') = self.modifier_command.take() {
+ self.set_command_modifier(false);
+ if let Some(mvm) = self.movement.as_ref() {
+ match mvm {
+ PageMovement::Up(amount) => {
+ for c in self.new_cursor_pos.2.saturating_sub(*amount)
+ ..=self.new_cursor_pos.2
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::PageUp(multiplier) => {
+ for c in self.new_cursor_pos.2.saturating_sub(rows * multiplier)
+ ..=self.new_cursor_pos.2
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::Down(amount) => {
+ for c in self.new_cursor_pos.2
+ ..std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1)
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::PageDown(multiplier) => {
+ for c in self.new_cursor_pos.2
+ ..std::cmp::min(
+ self.new_cursor_pos.2 + rows * multiplier + 1,
+ self.length,
+ )
+ {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::Right(_) | PageMovement::Left(_) => {}
+ PageMovement::Home => {
+ for c in 0..=self.new_cursor_pos.2 {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ PageMovement::End => {
+ for c in self.new_cursor_pos.2..self.length {
+ let thread = self.get_thread_under_cursor(c);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ self.row_updates.push(thread);
+ }
+ }
+ }
+ }
+ }
if !self.row_updates.is_empty() {
/* certain rows need to be updated (eg an unseen message was just set seen)
* */
- let (upper_left, bottom_right) = area;
while let Some(row) = self.row_updates.pop() {
self.update_line(context, row);
let row: usize = self.order[&row];
- let rows = (get_y(bottom_right) - get_y(upper_left) + 1) / 3;
let page_no = (self.cursor_pos.2).wrapping_div(rows);
let top_idx = page_no * rows;
/* Update row only if it's currently visible */
- if row >= top_idx && row <= top_idx + rows {
+ if row >= top_idx && row < top_idx + rows {
let area = (
set_y(upper_left, get_y(upper_left) + (3 * (row % rows))),
set_y(bottom_right, get_y(upper_left) + (3 * (row % rows) + 2)),
@@ -1288,8 +1357,12 @@ impl Component for ConversationsListing {
key == shortcuts[ConversationsListing::DESCRIPTION]["select_entry"]
) =>
{
- let thread = self.get_thread_under_cursor(self.cursor_pos.2);
- self.selection.entry(thread).and_modify(|e| *e = !*e);
+ if self.modifier_active {
+ self.modifier_command = Some('s');
+ } else {
+ let thread = self.get_thread_under_cursor(self.cursor_pos.2);
+ self.selection.entry(thread).and_modify(|e| *e = !*e);
+ }
return true;
}
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {