Add shortcut panel

Concerns #63
embed
Manos Pitsidianakis 2019-03-02 19:25:11 +02:00
parent 12cc9950c7
commit d285913974
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
5 changed files with 88 additions and 1 deletions

View File

@ -45,6 +45,7 @@ use std::fmt;
use std::fmt::{Debug, Display};
use std::ops::{Deref, DerefMut};
use fnv::FnvHashMap;
use uuid::Uuid;
use super::{Key, StatusEvent, UIEvent, UIEventType};
@ -141,6 +142,8 @@ impl Entity {
}
}
pub type ShortcutMap = FnvHashMap<Key, String>;
/// Types implementing this Trait can draw on the terminal and receive events.
/// If a type wants to skip drawing if it has not changed anything, it can hold some flag in its
/// fields (eg self.dirty = false) and act upon that in their `draw` implementation.
@ -153,6 +156,8 @@ pub trait Component: Display + Debug + Send {
fn set_dirty(&mut self);
fn kill(&mut self, _id: EntityId) {}
fn set_id(&mut self, _id: EntityId) {}
fn get_shortcuts(&self) -> ShortcutMap { Default::default() }
}
/*

View File

@ -115,6 +115,14 @@ impl Component for Listing {
Listing::Threaded(l) => l.set_dirty(),
}
}
fn get_shortcuts(&self) -> ShortcutMap {
match self {
Listing::Compact(l) => l.get_shortcuts(),
Listing::Plain(l) => l.get_shortcuts(),
Listing::Threaded(l) => l.get_shortcuts(),
}
}
}
impl From<IndexStyle> for Listing {

View File

@ -523,4 +523,21 @@ impl Component for CompactListing {
}
self.dirty = true;
}
fn get_shortcuts(&self) -> ShortcutMap {
let mut map = self.view.as_ref().map(|p| p.get_shortcuts()).unwrap_or(ShortcutMap::default());
map.insert(Key::Char('\n'), "Open thread.".into());
map.insert(Key::PageUp, "Go to previous page.".into());
map.insert(Key::PageDown, "Go to next page.".into());
map.insert(Key::Char('i'), "Exit thread view.".into());
map.insert(Key::Char('J'), "Go to previous folder.".into());
map.insert(Key::Char('K'), "Go to next folder.".into());
map.insert(Key::Char('h'), "Go to previous account.".into());
map.insert(Key::Char('l'), "Go to next account.".into());
map.insert(Key::Char('m'), "Start new mail draft in new tab.".into());
map
}
}

View File

@ -91,13 +91,21 @@ impl Component for HSplit {
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
self.top.rcv_event(event, context) || self.bottom.rcv_event(event, context)
}
fn is_dirty(&self) -> bool {
self.top.component.is_dirty() || self.bottom.component.is_dirty()
}
fn set_dirty(&mut self) {
self.top.component.set_dirty();
self.bottom.component.set_dirty();
}
fn get_shortcuts(&self) -> ShortcutMap {
let mut top_map = self.top.get_shortcuts();
top_map.extend(self.bottom.get_shortcuts().into_iter());
top_map
}
}
/// A vertically split in half container.
@ -175,16 +183,25 @@ impl Component for VSplit {
.component
.draw(grid, ((mid + 1, get_y(upper_left)), bottom_right), context);
}
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
(self.left.rcv_event(event, context) || self.right.rcv_event(event, context))
}
fn is_dirty(&self) -> bool {
self.left.component.is_dirty() || self.right.component.is_dirty()
}
fn set_dirty(&mut self) {
self.left.component.set_dirty();
self.right.component.set_dirty();
}
fn get_shortcuts(&self) -> ShortcutMap {
let mut right_map = self.right.get_shortcuts();
right_map.extend(self.left.get_shortcuts().into_iter());
right_map
}
}
#[derive(Debug)]
@ -632,6 +649,10 @@ impl Component for StatusBar {
fn set_dirty(&mut self) {
self.dirty = true;
}
fn get_shortcuts(&self) -> ShortcutMap {
self.container.get_shortcuts()
}
}
// A box with a text content.
@ -718,6 +739,8 @@ impl Component for Progress {
pub struct Tabbed {
children: Vec<Entity>,
cursor_pos: usize,
show_shortcuts: bool,
}
impl Tabbed {
@ -725,6 +748,7 @@ impl Tabbed {
Tabbed {
children: children.into_iter().map(Entity::from).collect(),
cursor_pos: 0,
show_shortcuts: false,
}
}
fn draw_tabs(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
@ -791,6 +815,34 @@ impl Component for Tabbed {
} else {
self.children[self.cursor_pos].draw(grid, area, context);
}
if self.show_shortcuts {
let area = (
pos_inc(upper_left!(area), (2, 1)), set_x(bottom_right!(area), get_x(bottom_right!(area)).saturating_sub(2)));
clear_area(grid, area);
create_box(grid, area);
// TODO: print into a pager
for (idx, (k, v)) in self.children[self.cursor_pos].get_shortcuts().into_iter().enumerate() {
let (x, y) = write_string_to_grid(
&format!("{:?}", k),
grid,
Color::Byte(29),
Color::Default,
(pos_inc(upper_left!(area), (2, 1 + idx)), set_x(bottom_right!(area), get_x(bottom_right!(area)).saturating_sub(2))),
false,
);
write_string_to_grid(
&v,
grid,
Color::Default,
Color::Default,
((x + 2, y), set_x(bottom_right!(area), get_x(bottom_right!(area)).saturating_sub(2))),
false,
);
};
context.dirty_areas.push_back(area);
}
}
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
match event.event_type {
@ -799,6 +851,11 @@ impl Component for Tabbed {
self.set_dirty();
return true;
}
UIEventType::Input(Key::Char('?')) => {
self.show_shortcuts = !self.show_shortcuts;
self.set_dirty();
return true;
}
UIEventType::Action(Tab(NewDraft)) => {
self.add_component(Box::new(Composer::default()));
self.cursor_pos = self.children.len() - 1;

View File

@ -26,7 +26,7 @@ use termion::event::Event as TermionEvent;
use termion::event::Key as TermionKey;
use termion::input::TermRead;
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Key {
/// Backspace.
Backspace,