tek/src/devices/help.rs

103 lines
3.5 KiB
Rust

//! Help modal / command palette.
use crate::{core::*, view::*};
/// Command palette.
pub struct HelpModal {
cursor: usize,
search: Option<String>,
exited: bool,
}
impl HelpModal {
pub fn new () -> Self {
Self { cursor: 0, search: None, exited: false }
}
}
impl Exit for HelpModal {
fn exited (&self) -> bool {
self.exited
}
fn exit (&mut self) {
self.exited = true;
}
}
render!(HelpModal |self, buf, area|{
for cell in buf.content.iter_mut() {
cell.bg = ratatui::style::Color::Rgb(30,30,30);
cell.fg = ratatui::style::Color::Rgb(100,100,100);
cell.modifier = ratatui::style::Modifier::DIM;
}
let width = 64.min(area.width * 3 / 5);
let height = 20.min(area.width * 3 / 5);
let x = area.x + (area.width - width) / 2;
let y = area.y + (area.height - height) / 2;
let area = Rect { x, y, width, height };
fill_fg(buf, area, Color::Reset);
fill_bg(buf, area, Nord::bg_lo(true, true));
fill_char(buf, area, ' ');
let x = area.x + 2;
let y = area.y + 1;
"Command:"
.blit(buf, x, y, Some(Style::default().bold()))?;
" ".repeat(area.width as usize - 13)
.blit(buf, x + 9, y, Some(Style::default().bg(Color::Reset)))?;
if let Some(search) = self.search.as_ref() {
search.blit(buf, x + 9, y, Some(Style::default().not_dim()))?;
}
let y = y + 1;
fill_char(buf, Rect { y, height: 1, ..area }, '-');
let y = y + 1;
for i in 0..height-3 {
let y = y + i;
if let Some(command) = crate::control::KEYMAP_FOCUS.get(i as usize) {
format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().white().bold()))?;
command.2.blit(buf, x + 11, y, Some(Style::default().white().bold()))?;
command.3.blit(buf, x + 26, y, Some(Style::default().white().dim()))?;
} else if let Some(command) = crate::control::KEYMAP_GLOBAL.get((i as usize) - crate::control::KEYMAP_FOCUS.len()) {
format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().white().bold()))?;
command.2.blit(buf, x + 11, y, Some(Style::default().white().bold()))?;
command.3.blit(buf, x + 26, y, Some(Style::default().white().dim()))?;
} else {
break
}
}
let hi_area = Rect { x: area.x + 1, width: area.width - 2, y: area.y + 3 + self.cursor as u16, height: 1 };
fill_bg(buf, hi_area, Nord::bg_hi(true, true));
fill_fg(buf, hi_area, Color::White);
Lozenge(Style::default()).draw(buf, area)
});
handle!(HelpModal |self, e| {
if handle_keymap(self, e, KEYMAP_HELP)? {
return Ok(true)
}
Ok(match e {
AppEvent::Input(Event::Key(KeyEvent {
code: KeyCode::Char(c),
modifiers: KeyModifiers::NONE, ..
})) => {
if self.search.is_none() {
self.search = Some(String::new());
}
self.search.as_mut().unwrap().push(*c);
true
},
_ => true
})
});
pub const KEYMAP_HELP: &'static [KeyBinding<HelpModal>] = keymap!(HelpModal {
[Esc, NONE, "help_close", "close help dialog", |modal: &mut HelpModal|{
modal.exit();
Ok(true)
}],
[Up, NONE, "help_prev", "select previous command", |modal: &mut HelpModal|{
modal.cursor = modal.cursor.saturating_sub(1);
Ok(true)
}],
[Down, NONE, "help_next", "select next command", |modal: &mut HelpModal|{
modal.cursor = modal.cursor + 1;
Ok(true)
}],
});