listing: add {previous,next}_entry shortcuts to quickly open other mail entries
When reading a mail entry, with Ctrl+n you can switch to the next entry, and with Ctrl+p to the previous one. They can be reconfigured by setting the shortcuts.listing.next_entry and shortcuts.listing.previous_entry settings.pull/237/head
parent
8cab9d9da8
commit
363f493099
|
@ -870,11 +870,19 @@ Select thread entry.
|
|||
.It Ic increase_sidebar
|
||||
Increase sidebar width.
|
||||
.\" default value
|
||||
.Pq Em C-p
|
||||
.Pq Em C-f
|
||||
.It Ic decrease_sidebar
|
||||
Decrease sidebar width.
|
||||
.\" default value
|
||||
.Pq Em C-o
|
||||
.Pq Em C-d
|
||||
.It Ic next_entry
|
||||
When reading a mail item, change focus on next entry according to the current sorting.
|
||||
.\" default value
|
||||
.Pq Em C-n
|
||||
.It Ic previous_entry
|
||||
When reading a mail item, change focus on previous entry according to the current sorting.
|
||||
.\" default value
|
||||
.Pq Em C-p
|
||||
.It Ic toggle_menu_visibility
|
||||
Toggle visibility of side menu in mail list.
|
||||
.\" default value
|
||||
|
|
|
@ -780,6 +780,8 @@ pub trait MailListingTrait: ListingTrait {
|
|||
pub trait ListingTrait: Component {
|
||||
fn coordinates(&self) -> (AccountHash, MailboxHash);
|
||||
fn set_coordinates(&mut self, _: (AccountHash, MailboxHash));
|
||||
fn next_entry(&mut self, context: &mut Context);
|
||||
fn prev_entry(&mut self, context: &mut Context);
|
||||
fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context);
|
||||
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context);
|
||||
fn filter(
|
||||
|
@ -1679,6 +1681,20 @@ impl Component for Listing {
|
|||
self.component
|
||||
.set_modifier_command(Some(Modifier::Intersection));
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if self.component.unfocused()
|
||||
&& shortcut!(key == shortcuts[Shortcuts::LISTING]["next_entry"]) =>
|
||||
{
|
||||
self.component.next_entry(context);
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if self.component.unfocused()
|
||||
&& shortcut!(
|
||||
key == shortcuts[Shortcuts::LISTING]["previous_entry"]
|
||||
) =>
|
||||
{
|
||||
self.component.prev_entry(context);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -584,6 +584,43 @@ impl ListingTrait for CompactListing {
|
|||
self.rows.row_updates.clear();
|
||||
}
|
||||
|
||||
fn next_entry(&mut self, context: &mut Context) {
|
||||
if self
|
||||
.get_thread_under_cursor(self.cursor_pos.2 + 1)
|
||||
.is_some()
|
||||
{
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Down(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 += 1;
|
||||
self.new_cursor_pos.2 += 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.new_cursor_pos.2 -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn prev_entry(&mut self, context: &mut Context) {
|
||||
if self.cursor_pos.2 == 0 {
|
||||
return;
|
||||
}
|
||||
if self
|
||||
.get_thread_under_cursor(self.cursor_pos.2 - 1)
|
||||
.is_some()
|
||||
{
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Up(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.new_cursor_pos.2 -= 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 += 1;
|
||||
self.new_cursor_pos.2 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
|
||||
let thread_hash = if let Some(h) = self.get_thread_under_cursor(idx) {
|
||||
h
|
||||
|
@ -861,8 +898,24 @@ impl ListingTrait for CompactListing {
|
|||
self.force_draw = true;
|
||||
}
|
||||
Focus::Entry => {
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
if let Some((thread_hash, env_hash)) = self
|
||||
.get_thread_under_cursor(self.cursor_pos.2)
|
||||
.and_then(|thread| self.rows.thread_to_env.get(&thread).map(|e| (thread, e[0])))
|
||||
{
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.kick_parent(
|
||||
self.parent,
|
||||
ListingMessage::OpenEntryUnderCursor {
|
||||
thread_hash,
|
||||
env_hash,
|
||||
show_thread: true,
|
||||
},
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Focus::EntryFullscreen => {
|
||||
self.dirty = true;
|
||||
|
@ -1738,23 +1791,8 @@ impl Component for CompactListing {
|
|||
&& (shortcut!(k == shortcuts[Shortcuts::LISTING]["open_entry"])
|
||||
|| shortcut!(k == shortcuts[Shortcuts::LISTING]["focus_right"])) =>
|
||||
{
|
||||
if let Some((thread_hash, env_hash)) = self
|
||||
.get_thread_under_cursor(self.cursor_pos.2)
|
||||
.and_then(|thread| {
|
||||
self.rows.thread_to_env.get(&thread).map(|e| (thread, e[0]))
|
||||
})
|
||||
{
|
||||
self.kick_parent(
|
||||
self.parent,
|
||||
ListingMessage::OpenEntryUnderCursor {
|
||||
thread_hash,
|
||||
env_hash,
|
||||
show_thread: true,
|
||||
},
|
||||
context,
|
||||
);
|
||||
self.set_focus(Focus::Entry, context);
|
||||
}
|
||||
self.set_focus(Focus::Entry, context);
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref k)
|
||||
|
|
|
@ -397,6 +397,43 @@ impl ListingTrait for ConversationsListing {
|
|||
self.rows.clear();
|
||||
}
|
||||
|
||||
fn next_entry(&mut self, context: &mut Context) {
|
||||
if self
|
||||
.get_thread_under_cursor(self.cursor_pos.2 + 1)
|
||||
.is_some()
|
||||
{
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Down(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 += 1;
|
||||
self.new_cursor_pos.2 += 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.new_cursor_pos.2 -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn prev_entry(&mut self, context: &mut Context) {
|
||||
if self.cursor_pos.2 == 0 {
|
||||
return;
|
||||
}
|
||||
if self
|
||||
.get_thread_under_cursor(self.cursor_pos.2 - 1)
|
||||
.is_some()
|
||||
{
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Up(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.new_cursor_pos.2 -= 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 += 1;
|
||||
self.new_cursor_pos.2 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
|
||||
if self.length == 0 {
|
||||
return;
|
||||
|
@ -605,8 +642,24 @@ impl ListingTrait for ConversationsListing {
|
|||
self.force_draw = true;
|
||||
}
|
||||
Focus::Entry => {
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
if let Some((thread_hash, env_hash)) = self
|
||||
.get_thread_under_cursor(self.cursor_pos.2)
|
||||
.and_then(|thread| self.rows.thread_to_env.get(&thread).map(|e| (thread, e[0])))
|
||||
{
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.kick_parent(
|
||||
self.parent,
|
||||
ListingMessage::OpenEntryUnderCursor {
|
||||
thread_hash,
|
||||
env_hash,
|
||||
show_thread: true,
|
||||
},
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Focus::EntryFullscreen => {}
|
||||
}
|
||||
|
@ -1296,23 +1349,8 @@ impl Component for ConversationsListing {
|
|||
&& (shortcut!(k == shortcuts[Shortcuts::LISTING]["open_entry"])
|
||||
|| shortcut!(k == shortcuts[Shortcuts::LISTING]["focus_right"])) =>
|
||||
{
|
||||
if let Some((thread_hash, env_hash)) = self
|
||||
.get_thread_under_cursor(self.cursor_pos.2)
|
||||
.and_then(|thread| {
|
||||
self.rows.thread_to_env.get(&thread).map(|e| (thread, e[0]))
|
||||
})
|
||||
{
|
||||
self.kick_parent(
|
||||
self.parent,
|
||||
ListingMessage::OpenEntryUnderCursor {
|
||||
thread_hash,
|
||||
env_hash,
|
||||
show_thread: true,
|
||||
},
|
||||
context,
|
||||
);
|
||||
self.set_focus(Focus::Entry, context);
|
||||
}
|
||||
self.set_focus(Focus::Entry, context);
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref k)
|
||||
|
|
|
@ -71,6 +71,10 @@ impl ListingTrait for OfflineListing {
|
|||
self.cursor_pos = coordinates;
|
||||
}
|
||||
|
||||
fn next_entry(&mut self, _: &mut Context) {}
|
||||
|
||||
fn prev_entry(&mut self, _: &mut Context) {}
|
||||
|
||||
fn highlight_line(
|
||||
&mut self,
|
||||
_grid: &mut CellBuffer,
|
||||
|
|
|
@ -321,6 +321,37 @@ impl ListingTrait for PlainListing {
|
|||
self.rows.row_updates.clear();
|
||||
}
|
||||
|
||||
fn next_entry(&mut self, context: &mut Context) {
|
||||
if self.get_env_under_cursor(self.cursor_pos.2 + 1).is_some() {
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Down(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 += 1;
|
||||
self.new_cursor_pos.2 += 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.new_cursor_pos.2 -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn prev_entry(&mut self, context: &mut Context) {
|
||||
if self.cursor_pos.2 == 0 {
|
||||
return;
|
||||
}
|
||||
if self.get_env_under_cursor(self.cursor_pos.2 - 1).is_some() {
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Up(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.new_cursor_pos.2 -= 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 += 1;
|
||||
self.new_cursor_pos.2 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
|
||||
let i = if let Some(i) = self.get_env_under_cursor(idx) {
|
||||
i
|
||||
|
@ -606,6 +637,8 @@ impl ListingTrait for PlainListing {
|
|||
},
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Focus::EntryFullscreen => {
|
||||
|
|
|
@ -435,6 +435,33 @@ impl ListingTrait for ThreadListing {
|
|||
(self.new_cursor_pos.0, self.new_cursor_pos.1)
|
||||
}
|
||||
|
||||
fn next_entry(&mut self, context: &mut Context) {
|
||||
if self.get_env_under_cursor(self.cursor_pos.2 + 1).is_some() {
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Down(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 += 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn prev_entry(&mut self, context: &mut Context) {
|
||||
if self.cursor_pos.2 == 0 {
|
||||
return;
|
||||
}
|
||||
if self.get_env_under_cursor(self.cursor_pos.2 - 1).is_some() {
|
||||
// TODO: makes this less ugly.
|
||||
self.movement = Some(PageMovement::Up(1));
|
||||
self.force_draw = true;
|
||||
self.dirty = true;
|
||||
self.cursor_pos.2 -= 1;
|
||||
self.set_focus(Focus::Entry, context);
|
||||
self.cursor_pos.2 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) {
|
||||
self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
|
||||
self.focus = Focus::None;
|
||||
|
@ -674,6 +701,8 @@ impl ListingTrait for ThreadListing {
|
|||
},
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Focus::EntryFullscreen => {
|
||||
|
|
|
@ -168,8 +168,10 @@ shortcut_key_values! { "listing",
|
|||
diff_modifier |> "Difference modifier." |> Key::Ctrl('d'),
|
||||
intersection_modifier |> "Intersection modifier." |> Key::Ctrl('i'),
|
||||
select_entry |> "Select thread entry." |> Key::Char('v'),
|
||||
increase_sidebar |> "Increase sidebar width." |> Key::Ctrl('p'),
|
||||
decrease_sidebar |> "Decrease sidebar width." |> Key::Ctrl('o'),
|
||||
increase_sidebar |> "Increase sidebar width." |> Key::Ctrl('f'),
|
||||
decrease_sidebar |> "Decrease sidebar width." |> Key::Ctrl('d'),
|
||||
next_entry |> "Focus on next entry." |> Key::Ctrl('n'),
|
||||
previous_entry |> "Focus on previous entry." |> Key::Ctrl('p'),
|
||||
toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`'),
|
||||
focus_left |> "Switch focus on the left." |> Key::Left,
|
||||
focus_right |> "Switch focus on the right." |> Key::Right,
|
||||
|
|
Loading…
Reference in New Issue