listing: add set operations to range select actions

Add symmetric difference (default), union, difference and intersection
modifiers for selecting ranges. That way you can quickly construct the
selection set you need.
jmap-eventsource
Manos Pitsidianakis 2020-10-21 14:30:44 +03:00
parent 05ef863a45
commit 594a2bd0dd
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
7 changed files with 365 additions and 60 deletions

View File

@ -43,6 +43,20 @@ pub use self::plain::*;
mod offline; mod offline;
pub use self::offline::*; pub use self::offline::*;
#[derive(Debug, Copy, PartialEq, Clone)]
pub enum Modifier {
SymmetricDifference,
Union,
Difference,
Intersection,
}
impl Default for Modifier {
fn default() -> Self {
Modifier::SymmetricDifference
}
}
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct DataColumns { pub struct DataColumns {
pub columns: [CellBuffer; 12], pub columns: [CellBuffer; 12],
@ -372,7 +386,12 @@ pub trait ListingTrait: Component {
_context: &Context, _context: &Context,
) { ) {
} }
fn set_command_modifier(&mut self, _is_active: bool) {} fn unfocused(&self) -> bool;
fn set_modifier_active(&mut self, _new_val: bool) {}
fn set_modifier_command(&mut self, _new_val: Option<Modifier>) {}
fn modifier_command(&self) -> Option<Modifier> {
None
}
fn set_movement(&mut self, mvm: PageMovement); fn set_movement(&mut self, mvm: PageMovement);
} }
@ -711,14 +730,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -764,14 +783,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -887,14 +906,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -910,14 +929,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -933,14 +952,14 @@ impl Component for Listing {
1 1
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() { } else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
mult mult
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -956,14 +975,14 @@ impl Component for Listing {
1 1
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() { } else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
mult mult
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -1022,6 +1041,31 @@ impl Component for Listing {
} }
return true; return true;
} }
UIEvent::Input(ref key)
if !self.component.unfocused()
&& shortcut!(key == shortcuts[Listing::DESCRIPTION]["union_modifier"])
&& self.component.modifier_command().is_some() =>
{
self.component.set_modifier_command(Some(Modifier::Union));
}
UIEvent::Input(ref key)
if !self.component.unfocused()
&& shortcut!(key == shortcuts[Listing::DESCRIPTION]["diff_modifier"])
&& self.component.modifier_command().is_some() =>
{
self.component
.set_modifier_command(Some(Modifier::Difference));
}
UIEvent::Input(ref key)
if !self.component.unfocused()
&& shortcut!(
key == shortcuts[Listing::DESCRIPTION]["intersection_modifier"]
)
&& self.component.modifier_command().is_some() =>
{
self.component
.set_modifier_command(Some(Modifier::Intersection));
}
_ => {} _ => {}
} }
} else if self.focus == ListingFocus::Menu { } else if self.focus == ListingFocus::Menu {
@ -1055,14 +1099,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -1109,14 +1153,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -1165,14 +1209,14 @@ impl Component for Listing {
1 1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() { } else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount amount
} else { } else {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -1240,7 +1284,7 @@ impl Component for Listing {
} }
UIEvent::Input(Key::Esc) | UIEvent::Input(Key::Alt('')) if !self.cmd_buf.is_empty() => { UIEvent::Input(Key::Esc) | UIEvent::Input(Key::Alt('')) if !self.cmd_buf.is_empty() => {
self.cmd_buf.clear(); self.cmd_buf.clear();
self.component.set_command_modifier(false); self.component.set_modifier_active(false);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); .push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
@ -1248,7 +1292,7 @@ impl Component for Listing {
} }
UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => { UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
self.cmd_buf.push(c); self.cmd_buf.push(c);
self.component.set_command_modifier(true); self.component.set_modifier_active(true);
context context
.replies .replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufSet( .push_back(UIEvent::StatusEvent(StatusEvent::BufSet(

View File

@ -19,7 +19,6 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>. * along with meli. If not, see <http://www.gnu.org/licenses/>.
*/ */
use super::EntryStrings;
use super::*; use super::*;
use crate::components::PageMovement; use crate::components::PageMovement;
use crate::jobs::JoinHandle; use crate::jobs::JoinHandle;
@ -153,7 +152,7 @@ pub struct CompactListing {
movement: Option<PageMovement>, movement: Option<PageMovement>,
modifier_active: bool, modifier_active: bool,
modifier_command: Option<char>, modifier_command: Option<Modifier>,
id: ComponentId, id: ComponentId,
} }
@ -595,7 +594,9 @@ impl ListingTrait for CompactListing {
self.highlight_line(grid, new_area, *idx, context); self.highlight_line(grid, new_area, *idx, context);
context.dirty_areas.push_back(new_area); context.dirty_areas.push_back(new_area);
} }
return; if !self.force_draw {
return;
}
} else if self.cursor_pos != self.new_cursor_pos { } else if self.cursor_pos != self.new_cursor_pos {
self.cursor_pos = self.new_cursor_pos; self.cursor_pos = self.new_cursor_pos;
} }
@ -852,8 +853,20 @@ impl ListingTrait for CompactListing {
} }
} }
fn set_command_modifier(&mut self, is_active: bool) { fn unfocused(&self) -> bool {
self.modifier_active = is_active; self.unfocused
}
fn set_modifier_active(&mut self, new_val: bool) {
self.modifier_active = new_val;
}
fn set_modifier_command(&mut self, new_val: Option<Modifier>) {
self.modifier_command = new_val;
}
fn modifier_command(&self) -> Option<Modifier> {
self.modifier_command
} }
fn set_movement(&mut self, mvm: PageMovement) { fn set_movement(&mut self, mvm: PageMovement) {
@ -1406,8 +1419,7 @@ impl Component for CompactListing {
let (upper_left, bottom_right) = area; let (upper_left, bottom_right) = area;
let rows = get_y(bottom_right) - get_y(upper_left) + 1; let rows = get_y(bottom_right) - get_y(upper_left) + 1;
if let Some('s') = self.modifier_command.take() { if let Some(modifier) = self.modifier_command.take() {
self.set_command_modifier(false);
if let Some(mvm) = self.movement.as_ref() { if let Some(mvm) = self.movement.as_ref() {
match mvm { match mvm {
PageMovement::Up(amount) => { PageMovement::Up(amount) => {
@ -1415,16 +1427,47 @@ impl Component for CompactListing {
..=self.new_cursor_pos.2 ..=self.new_cursor_pos.2
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (0..self.new_cursor_pos.2.saturating_sub(*amount))
.chain((self.new_cursor_pos.2 + 2)..self.length)
{
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::PageUp(multiplier) => { PageMovement::PageUp(multiplier) => {
for c in self.new_cursor_pos.2.saturating_sub(rows * multiplier) for c in self.new_cursor_pos.2.saturating_sub(rows * multiplier)
..=self.new_cursor_pos.2 ..=self.new_cursor_pos.2
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
} }
@ -1433,9 +1476,30 @@ impl Component for CompactListing {
..std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1) ..std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1)
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (0..self.new_cursor_pos.2).chain(
(std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1)
+ 1)..self.length,
) {
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::PageDown(multiplier) => { PageMovement::PageDown(multiplier) => {
for c in self.new_cursor_pos.2 for c in self.new_cursor_pos.2
@ -1445,27 +1509,87 @@ impl Component for CompactListing {
) )
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (0..self.new_cursor_pos.2).chain(
(std::cmp::min(
self.new_cursor_pos.2 + rows * multiplier + 1,
self.length,
) + 1)..self.length,
) {
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::Right(_) | PageMovement::Left(_) => {} PageMovement::Right(_) | PageMovement::Left(_) => {}
PageMovement::Home => { PageMovement::Home => {
for c in 0..=self.new_cursor_pos.2 { for c in 0..=self.new_cursor_pos.2 {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (self.new_cursor_pos.2 + 1)..self.length {
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::End => { PageMovement::End => {
for c in self.new_cursor_pos.2..self.length { for c in self.new_cursor_pos.2..self.length {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
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 = false);
self.row_updates.push(thread);
}
}
} }
} }
} }
self.force_draw = true;
} }
if !self.row_updates.is_empty() { if !self.row_updates.is_empty() {
@ -1540,12 +1664,10 @@ impl Component for CompactListing {
} }
UIEvent::Input(ref key) UIEvent::Input(ref key)
if !self.unfocused if !self.unfocused
&& shortcut!( && shortcut!(key == shortcuts[Listing::DESCRIPTION]["select_entry"]) =>
key == shortcuts[CompactListing::DESCRIPTION]["select_entry"]
) =>
{ {
if self.modifier_active { if self.modifier_active && self.modifier_command.is_none() {
self.modifier_command = Some('s'); self.modifier_command = Some(Modifier::default());
} else { } else {
let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2); let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2);
self.selection.entry(thread_hash).and_modify(|e| *e = !*e); self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
@ -1783,6 +1905,8 @@ impl Component for CompactListing {
let config_map = context.settings.shortcuts.compact_listing.key_values(); let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(CompactListing::DESCRIPTION, config_map); map.insert(CompactListing::DESCRIPTION, config_map);
let config_map = context.settings.shortcuts.listing.key_values();
map.insert(Listing::DESCRIPTION, config_map);
map map
} }

View File

@ -120,7 +120,7 @@ pub struct ConversationsListing {
movement: Option<PageMovement>, movement: Option<PageMovement>,
modifier_active: bool, modifier_active: bool,
modifier_command: Option<char>, modifier_command: Option<Modifier>,
id: ComponentId, id: ComponentId,
} }
@ -868,8 +868,20 @@ impl ListingTrait for ConversationsListing {
} }
} }
fn set_command_modifier(&mut self, is_active: bool) { fn unfocused(&self) -> bool {
self.modifier_active = is_active; self.unfocused
}
fn set_modifier_active(&mut self, new_val: bool) {
self.modifier_active = new_val;
}
fn set_modifier_command(&mut self, new_val: Option<Modifier>) {
self.modifier_command = new_val;
}
fn modifier_command(&self) -> Option<Modifier> {
self.modifier_command
} }
fn set_movement(&mut self, mvm: PageMovement) { fn set_movement(&mut self, mvm: PageMovement) {
@ -1260,8 +1272,7 @@ impl Component for ConversationsListing {
} }
let (upper_left, bottom_right) = area; let (upper_left, bottom_right) = area;
let rows = (get_y(bottom_right) - get_y(upper_left) + 1) / 3; let rows = (get_y(bottom_right) - get_y(upper_left) + 1) / 3;
if let Some('s') = self.modifier_command.take() { if let Some(modifier) = self.modifier_command.take() {
self.set_command_modifier(false);
if let Some(mvm) = self.movement.as_ref() { if let Some(mvm) = self.movement.as_ref() {
match mvm { match mvm {
PageMovement::Up(amount) => { PageMovement::Up(amount) => {
@ -1269,16 +1280,47 @@ impl Component for ConversationsListing {
..=self.new_cursor_pos.2 ..=self.new_cursor_pos.2
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (0..self.new_cursor_pos.2.saturating_sub(*amount))
.chain((self.new_cursor_pos.2 + 2)..self.length)
{
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::PageUp(multiplier) => { PageMovement::PageUp(multiplier) => {
for c in self.new_cursor_pos.2.saturating_sub(rows * multiplier) for c in self.new_cursor_pos.2.saturating_sub(rows * multiplier)
..=self.new_cursor_pos.2 ..=self.new_cursor_pos.2
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
} }
@ -1287,9 +1329,30 @@ impl Component for ConversationsListing {
..std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1) ..std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1)
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (0..self.new_cursor_pos.2).chain(
(std::cmp::min(self.length, self.new_cursor_pos.2 + amount + 1)
+ 1)..self.length,
) {
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::PageDown(multiplier) => { PageMovement::PageDown(multiplier) => {
for c in self.new_cursor_pos.2 for c in self.new_cursor_pos.2
@ -1299,24 +1362,83 @@ impl Component for ConversationsListing {
) )
{ {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (0..self.new_cursor_pos.2).chain(
(std::cmp::min(
self.new_cursor_pos.2 + rows * multiplier + 1,
self.length,
) + 1)..self.length,
) {
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::Right(_) | PageMovement::Left(_) => {} PageMovement::Right(_) | PageMovement::Left(_) => {}
PageMovement::Home => { PageMovement::Home => {
for c in 0..=self.new_cursor_pos.2 { for c in 0..=self.new_cursor_pos.2 {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
for c in (self.new_cursor_pos.2 + 1)..self.length {
let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = false);
self.row_updates.push(thread);
}
}
} }
PageMovement::End => { PageMovement::End => {
for c in self.new_cursor_pos.2..self.length { for c in self.new_cursor_pos.2..self.length {
let thread = self.get_thread_under_cursor(c); let thread = self.get_thread_under_cursor(c);
self.selection.entry(thread).and_modify(|e| *e = !*e); match modifier {
Modifier::SymmetricDifference => {
self.selection.entry(thread).and_modify(|e| *e = !*e);
}
Modifier::Union => {
self.selection.entry(thread).and_modify(|e| *e = true);
}
Modifier::Difference => {
self.selection.entry(thread).and_modify(|e| *e = false);
}
Modifier::Intersection => {}
}
self.row_updates.push(thread); self.row_updates.push(thread);
} }
if modifier == Modifier::Intersection {
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 = false);
self.row_updates.push(thread);
}
}
} }
} }
} }
@ -1402,12 +1524,10 @@ impl Component for ConversationsListing {
} }
UIEvent::Input(ref key) UIEvent::Input(ref key)
if !self.unfocused if !self.unfocused
&& shortcut!( && shortcut!(key == shortcuts[Listing::DESCRIPTION]["select_entry"]) =>
key == shortcuts[ConversationsListing::DESCRIPTION]["select_entry"]
) =>
{ {
if self.modifier_active { if self.modifier_active && self.modifier_command.is_none() {
self.modifier_command = Some('s'); self.modifier_command = Some(Modifier::default());
} else { } else {
let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2); let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2);
self.selection.entry(thread_hash).and_modify(|e| *e = !*e); self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
@ -1631,6 +1751,8 @@ impl Component for ConversationsListing {
let config_map = context.settings.shortcuts.compact_listing.key_values(); let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(ConversationsListing::DESCRIPTION, config_map); map.insert(ConversationsListing::DESCRIPTION, config_map);
let config_map = context.settings.shortcuts.listing.key_values();
map.insert(Listing::DESCRIPTION, config_map);
map map
} }

View File

@ -79,6 +79,10 @@ impl ListingTrait for OfflineListing {
fn draw_list(&mut self, _: &mut CellBuffer, _: Area, _: &mut Context) {} fn draw_list(&mut self, _: &mut CellBuffer, _: Area, _: &mut Context) {}
fn unfocused(&self) -> bool {
false
}
fn set_movement(&mut self, _: PageMovement) {} fn set_movement(&mut self, _: PageMovement) {}
} }

View File

@ -703,6 +703,10 @@ impl ListingTrait for PlainListing {
} }
} }
fn unfocused(&self) -> bool {
self.unfocused
}
fn set_movement(&mut self, mvm: PageMovement) { fn set_movement(&mut self, mvm: PageMovement) {
self.movement = Some(mvm); self.movement = Some(mvm);
self.set_dirty(true); self.set_dirty(true);
@ -1182,9 +1186,7 @@ impl Component for PlainListing {
} }
UIEvent::Input(ref key) UIEvent::Input(ref key)
if !self.unfocused if !self.unfocused
&& shortcut!( && shortcut!(key == shortcuts[Listing::DESCRIPTION]["select_entry"]) =>
key == shortcuts[PlainListing::DESCRIPTION]["select_entry"]
) =>
{ {
let env_hash = self.get_env_under_cursor(self.cursor_pos.2, context); let env_hash = self.get_env_under_cursor(self.cursor_pos.2, context);
self.selection.entry(env_hash).and_modify(|e| *e = !*e); self.selection.entry(env_hash).and_modify(|e| *e = !*e);
@ -1388,6 +1390,8 @@ impl Component for PlainListing {
let config_map = context.settings.shortcuts.compact_listing.key_values(); let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(PlainListing::DESCRIPTION, config_map); map.insert(PlainListing::DESCRIPTION, config_map);
let config_map = context.settings.shortcuts.listing.key_values();
map.insert(Listing::DESCRIPTION, config_map);
map map
} }

View File

@ -734,6 +734,10 @@ impl ListingTrait for ThreadListing {
} }
} }
fn unfocused(&self) -> bool {
self.unfocused
}
fn set_movement(&mut self, mvm: PageMovement) { fn set_movement(&mut self, mvm: PageMovement) {
self.movement = Some(mvm); self.movement = Some(mvm);
self.set_dirty(true); self.set_dirty(true);

View File

@ -160,8 +160,7 @@ shortcut_key_values! { "compact-listing",
/// Shortcut listing for a mail listing in compact mode. /// Shortcut listing for a mail listing in compact mode.
pub struct CompactListingShortcuts { pub struct CompactListingShortcuts {
exit_thread |> "Exit thread view." |> Key::Char('i'), exit_thread |> "Exit thread view." |> Key::Char('i'),
open_thread |> "Open thread." |> Key::Char('\n'), open_thread |> "Open thread." |> Key::Char('\n')
select_entry |> "Select thread entry." |> Key::Char('v')
} }
} }
@ -181,6 +180,10 @@ shortcut_key_values! { "listing",
search |> "Search within list of e-mails." |> Key::Char('/'), search |> "Search within list of e-mails." |> Key::Char('/'),
refresh |> "Manually request a mailbox refresh." |> Key::F(5), refresh |> "Manually request a mailbox refresh." |> Key::F(5),
set_seen |> "Set thread as seen." |> Key::Char('n'), set_seen |> "Set thread as seen." |> Key::Char('n'),
union_modifier |> "Union modifier." |> Key::Ctrl('u'),
diff_modifier |> "Difference modifier." |> Key::Ctrl('d'),
intersection_modifier |> "Intersection modifier." |> Key::Ctrl('i'),
select_entry |> "Select thread entry." |> Key::Char('v'),
toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`') toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`')
} }
} }