ui: scroll in shortcuts panel
parent
91ae539de1
commit
6d40a57a2e
|
@ -1140,6 +1140,9 @@ pub struct Tabbed {
|
||||||
cursor_pos: usize,
|
cursor_pos: usize,
|
||||||
|
|
||||||
show_shortcuts: bool,
|
show_shortcuts: bool,
|
||||||
|
help_screen_cursor: (usize, usize),
|
||||||
|
help_content: CellBuffer,
|
||||||
|
help_curr_views: ShortcutMaps,
|
||||||
|
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
id: ComponentId,
|
id: ComponentId,
|
||||||
|
@ -1153,6 +1156,9 @@ impl Tabbed {
|
||||||
children,
|
children,
|
||||||
cursor_pos: 0,
|
cursor_pos: 0,
|
||||||
show_shortcuts: false,
|
show_shortcuts: false,
|
||||||
|
help_content: CellBuffer::default(),
|
||||||
|
help_screen_cursor: (0, 0),
|
||||||
|
help_curr_views: ShortcutMaps::default(),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::new_v4(),
|
||||||
}
|
}
|
||||||
|
@ -1232,9 +1238,18 @@ impl Component for Tabbed {
|
||||||
set_x(upper_left!(area), get_x(bottom_right!(area))),
|
set_x(upper_left!(area), get_x(bottom_right!(area))),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
self.dirty = false;
|
context.dirty_areas.push_back((
|
||||||
|
upper_left!(area),
|
||||||
|
set_x(upper_left!(area), get_x(bottom_right!(area))),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If children are dirty but self isn't and the shortcuts panel is visible, it will get
|
||||||
|
* overwritten. */
|
||||||
|
let must_redraw_shortcuts: bool = self.show_shortcuts && !self.dirty && self.is_dirty();
|
||||||
|
|
||||||
|
/* children should be drawn after the shortcuts/help panel lest they overwrite the panel on
|
||||||
|
* the grid. the drawing order is determined by the dirty_areas queue which is LIFO */
|
||||||
if self.children.len() > 1 {
|
if self.children.len() > 1 {
|
||||||
self.draw_tabs(
|
self.draw_tabs(
|
||||||
grid,
|
grid,
|
||||||
|
@ -1254,7 +1269,7 @@ impl Component for Tabbed {
|
||||||
self.children[self.cursor_pos].draw(grid, area, context);
|
self.children[self.cursor_pos].draw(grid, area, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.show_shortcuts {
|
if (self.show_shortcuts && self.dirty) || must_redraw_shortcuts {
|
||||||
let area = (
|
let area = (
|
||||||
pos_inc(upper_left!(area), (2, 1)),
|
pos_inc(upper_left!(area), (2, 1)),
|
||||||
set_x(
|
set_x(
|
||||||
|
@ -1262,70 +1277,139 @@ impl Component for Tabbed {
|
||||||
get_x(bottom_right!(area)).saturating_sub(2),
|
get_x(bottom_right!(area)).saturating_sub(2),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
context.dirty_areas.push_back(area);
|
||||||
clear_area(grid, area);
|
clear_area(grid, area);
|
||||||
create_box(grid, area);
|
create_box(grid, area);
|
||||||
|
let area = (
|
||||||
let mut idx = 0;
|
pos_inc(upper_left!(area), (3, 2)),
|
||||||
// TODO: print into a pager
|
set_x(
|
||||||
for (desc, shortcuts) in self.children[self.cursor_pos]
|
bottom_right!(area),
|
||||||
.get_shortcuts(context)
|
get_x(bottom_right!(area)).saturating_sub(3),
|
||||||
.into_iter()
|
),
|
||||||
{
|
);
|
||||||
write_string_to_grid(
|
let children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
||||||
&desc,
|
if children_maps.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (children_maps == self.help_curr_views) && must_redraw_shortcuts {
|
||||||
|
let (width, height) = self.help_content.size();
|
||||||
|
let (cols, rows) = (width!(area), height!(area));
|
||||||
|
copy_area(
|
||||||
grid,
|
grid,
|
||||||
|
&self.help_content,
|
||||||
|
area,
|
||||||
|
(
|
||||||
|
(
|
||||||
|
std::cmp::min(
|
||||||
|
(width - 1).saturating_sub(cols),
|
||||||
|
self.help_screen_cursor.0,
|
||||||
|
),
|
||||||
|
std::cmp::min(
|
||||||
|
(height - 1).saturating_sub(rows),
|
||||||
|
self.help_screen_cursor.1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
std::cmp::min(self.help_screen_cursor.0 + cols, width - 1),
|
||||||
|
std::cmp::min(self.help_screen_cursor.1 + rows, height - 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.dirty = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.help_curr_views = children_maps;
|
||||||
|
let mut max_length = 5;
|
||||||
|
let mut max_width = "Use Up, Down, Left, Right to scroll.".len() + 3;
|
||||||
|
for (desc, shortcuts) in self.help_curr_views.iter() {
|
||||||
|
max_length += shortcuts.len() + 3;
|
||||||
|
max_width = std::cmp::max(
|
||||||
|
max_width,
|
||||||
|
std::cmp::max(
|
||||||
|
desc.len(),
|
||||||
|
shortcuts.keys().map(|k| k.len() + 5).max().unwrap_or(0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.help_content = CellBuffer::new(max_width, max_length + 2, Cell::default());
|
||||||
|
let (width, height) = self.help_content.size();
|
||||||
|
let (cols, rows) = (width!(area), height!(area));
|
||||||
|
if cols == 0 || rows == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* trim cursor if it's bigger than the help screen */
|
||||||
|
self.help_screen_cursor = (
|
||||||
|
std::cmp::min(width.saturating_sub(cols), self.help_screen_cursor.0),
|
||||||
|
std::cmp::min(height.saturating_sub(rows), self.help_screen_cursor.1),
|
||||||
|
);
|
||||||
|
|
||||||
|
/* In this case we will be scrolling, so show the user how to do it */
|
||||||
|
if height.wrapping_div(rows) > 0 || width.wrapping_div(cols) > 0 {
|
||||||
|
write_string_to_grid(
|
||||||
|
"Use Up, Down, Left, Right to scroll.",
|
||||||
|
&mut self.help_content,
|
||||||
Color::Default,
|
Color::Default,
|
||||||
Color::Default,
|
Color::Default,
|
||||||
Attr::Default,
|
Attr::Default,
|
||||||
(
|
((2, 0), (max_width.saturating_sub(2), max_length - 1)),
|
||||||
pos_inc(upper_left!(area), (2, 1 + idx)),
|
false,
|
||||||
set_x(
|
);
|
||||||
bottom_right!(area),
|
}
|
||||||
get_x(bottom_right!(area)).saturating_sub(2),
|
let mut idx = 0;
|
||||||
),
|
for (desc, shortcuts) in self.help_curr_views.iter() {
|
||||||
),
|
write_string_to_grid(
|
||||||
|
desc,
|
||||||
|
&mut self.help_content,
|
||||||
|
Color::Default,
|
||||||
|
Color::Default,
|
||||||
|
Attr::Default,
|
||||||
|
((2, 2 + idx), (max_width.saturating_sub(2), max_length - 1)),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
idx += 2;
|
idx += 2;
|
||||||
let mut shortcuts = shortcuts.into_iter().collect::<Vec<_>>();
|
let mut shortcuts = shortcuts.iter().collect::<Vec<_>>();
|
||||||
shortcuts.sort_unstable_by_key(|(ref k, _)| *k);
|
shortcuts.sort_unstable_by_key(|(ref k, _)| *k);
|
||||||
for (k, v) in shortcuts {
|
for (k, v) in shortcuts {
|
||||||
|
debug!(&(k, v));
|
||||||
let (x, y) = write_string_to_grid(
|
let (x, y) = write_string_to_grid(
|
||||||
&k,
|
&k,
|
||||||
grid,
|
&mut self.help_content,
|
||||||
Color::Byte(29),
|
Color::Byte(29),
|
||||||
Color::Default,
|
Color::Default,
|
||||||
Attr::Default,
|
Attr::Default,
|
||||||
(
|
((2, 2 + idx), (max_width.saturating_sub(2), max_length - 1)),
|
||||||
pos_inc(upper_left!(area), (2, 1 + idx)),
|
|
||||||
set_x(
|
|
||||||
bottom_right!(area),
|
|
||||||
get_x(bottom_right!(area)).saturating_sub(2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
write_string_to_grid(
|
write_string_to_grid(
|
||||||
&format!("{}", v),
|
&format!("{}", v),
|
||||||
grid,
|
&mut self.help_content,
|
||||||
Color::Default,
|
Color::Default,
|
||||||
Color::Default,
|
Color::Default,
|
||||||
Attr::Default,
|
Attr::Default,
|
||||||
(
|
((x + 2, y), (max_width.saturating_sub(2), max_length - 1)),
|
||||||
(x + 2, y),
|
|
||||||
set_x(
|
|
||||||
bottom_right!(area),
|
|
||||||
get_x(bottom_right!(area)).saturating_sub(2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
idx += 1;
|
idx += 1;
|
||||||
}
|
}
|
||||||
idx += 1;
|
idx += 1;
|
||||||
}
|
}
|
||||||
context.dirty_areas.push_back(area);
|
copy_area(
|
||||||
|
grid,
|
||||||
|
&self.help_content,
|
||||||
|
area,
|
||||||
|
(
|
||||||
|
(
|
||||||
|
std::cmp::min((width - 1).saturating_sub(cols), self.help_screen_cursor.0),
|
||||||
|
std::cmp::min((height - 1).saturating_sub(rows), self.help_screen_cursor.1),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
std::cmp::min(self.help_screen_cursor.0 + cols, width - 1),
|
||||||
|
std::cmp::min(self.help_screen_cursor.1 + rows, height - 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
self.dirty = false;
|
||||||
}
|
}
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
match *event {
|
match *event {
|
||||||
|
@ -1342,8 +1426,12 @@ impl Component for Tabbed {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
UIEvent::Input(Key::Char('?')) => {
|
UIEvent::Input(Key::Char('?')) => {
|
||||||
|
if self.show_shortcuts {
|
||||||
|
/* children below the shortcut overlay must be redrawn */
|
||||||
|
self.set_dirty();
|
||||||
|
}
|
||||||
self.show_shortcuts = !self.show_shortcuts;
|
self.show_shortcuts = !self.show_shortcuts;
|
||||||
self.set_dirty();
|
self.dirty = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
UIEvent::Action(Tab(NewDraft(account_idx, ref draft))) => {
|
UIEvent::Action(Tab(NewDraft(account_idx, ref draft))) => {
|
||||||
|
@ -1399,6 +1487,31 @@ impl Component for Tabbed {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UIEvent::Resize => {
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
UIEvent::Input(ref k) if self.show_shortcuts => {
|
||||||
|
match k {
|
||||||
|
Key::Up => {
|
||||||
|
self.help_screen_cursor.1 = self.help_screen_cursor.1.saturating_sub(1);
|
||||||
|
}
|
||||||
|
Key::Down => {
|
||||||
|
self.help_screen_cursor.1 = self.help_screen_cursor.1 + 1;
|
||||||
|
}
|
||||||
|
Key::Left => {
|
||||||
|
self.help_screen_cursor.0 = self.help_screen_cursor.0.saturating_sub(1);
|
||||||
|
}
|
||||||
|
Key::Right => {
|
||||||
|
self.help_screen_cursor.0 = self.help_screen_cursor.0 + 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
/* ignore, don't pass to components below the shortcut panel */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.children[self.cursor_pos].process_event(event, context)
|
self.children[self.cursor_pos].process_event(event, context)
|
||||||
|
|
Loading…
Reference in New Issue