diff --git a/crates/tek_core/src/command.rs b/crates/tek_core/src/command.rs index 870681d5..07ef059c 100644 --- a/crates/tek_core/src/command.rs +++ b/crates/tek_core/src/command.rs @@ -1,28 +1,7 @@ use crate::*; -pub trait Command: Sized { - fn run (&self, state: &mut T) -> Perhaps; -} - -pub const fn key (code: KeyCode) -> KeyEvent { - KeyEvent { - code, - modifiers: KeyModifiers::NONE, - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE - } -} - -pub const fn ctrl (key: KeyEvent) -> KeyEvent { - KeyEvent { modifiers: key.modifiers.union(KeyModifiers::CONTROL), ..key } -} - -pub const fn alt (key: KeyEvent) -> KeyEvent { - KeyEvent { modifiers: key.modifiers.union(KeyModifiers::ALT), ..key } -} - -pub const fn shift (key: KeyEvent) -> KeyEvent { - KeyEvent { modifiers: key.modifiers.union(KeyModifiers::SHIFT), ..key } +pub trait Command: Sized { + fn run (&self, state: &mut S) -> Perhaps; } pub trait HandleKey + Clone + 'static>: Sized { @@ -62,3 +41,23 @@ pub trait HandleKey + Clone + 'static>: Sized { } } } + +pub struct Menu, C: Command> { + pub items: Vec>, + pub index: usize, +} + +impl, C: Command> Menu { + pub const fn item (command: C, name: &'static str, key: &'static str) -> MenuItem { + MenuItem::Command(command, name, key) + } +} + +pub enum MenuItem, C: Command> { + /// Unused. + __(PhantomData, PhantomData), + /// A separator. Skip it. + Separator, + /// A menu item with command, description and hotkey. + Command(C, &'static str, &'static str) +} diff --git a/crates/tek_core/src/tui.rs b/crates/tek_core/src/tui.rs index c1d23c90..20e1baaa 100644 --- a/crates/tek_core/src/tui.rs +++ b/crates/tek_core/src/tui.rs @@ -1,7 +1,7 @@ use crate::*; pub(crate) use ratatui::buffer::Cell; pub(crate) use crossterm::{ExecutableCommand}; -pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers}; +pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}; pub use ratatui::prelude::{Rect, Style, Color, Buffer}; pub use ratatui::style::{Stylize, Modifier}; use ratatui::backend::{Backend, CrosstermBackend, ClearType}; @@ -133,23 +133,15 @@ impl Tui { buffer } } -pub struct TuiInput { - event: TuiEvent, - exited: Arc, -} +pub struct TuiInput { event: TuiEvent, exited: Arc, } impl Input for TuiInput { type Event = TuiEvent; - fn event (&self) -> &TuiEvent { - &self.event - } - fn is_done (&self) -> bool { - self.exited.fetch_and(true, Ordering::Relaxed) - } - fn done (&self) { - self.exited.store(true, Ordering::Relaxed); - } + fn event (&self) -> &TuiEvent { &self.event } + fn is_done (&self) -> bool { self.exited.fetch_and(true, Ordering::Relaxed) } + fn done (&self) { self.exited.store(true, Ordering::Relaxed); } } impl TuiInput { + // TODO remove pub fn handle_keymap (&self, state: &mut T, keymap: &KeyMap) -> Usually { match self.event() { TuiEvent::Input(crossterm::event::Event::Key(event)) => { @@ -167,84 +159,10 @@ impl TuiInput { pub type KeyHandler = &'static dyn Fn(&mut T)->Usually; pub type KeyBinding = (KeyCode, KeyModifiers, &'static str, &'static str, KeyHandler); pub type KeyMap = [KeyBinding]; -/// Define a keymap -#[macro_export] macro_rules! keymap { - ($T:ty { $([$k:ident $(($char:literal))?, $m:ident, $n: literal, $d: literal, $f: expr]),* $(,)? }) => { - &[ - $((KeyCode::$k $(($char))?, KeyModifiers::$m, $n, $d, &$f as KeyHandler<$T>)),* - ] as &'static [KeyBinding<$T>] - } -} -/// Define a key in a keymap -#[macro_export] macro_rules! map_key { - ($k:ident $(($char:literal))?, $m:ident, $n: literal, $d: literal, $f: expr) => { - (KeyCode::$k $(($char))?, KeyModifiers::$m, $n, $d, &$f as &dyn Fn()->Usually) - } -} -/// Shorthand for key match statement -#[macro_export] macro_rules! match_key { - ($event:expr, { - $($key:pat=>$block:expr),* $(,)? - }) => { - match $event { - $(crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: $key, - modifiers: crossterm::event::KeyModifiers::NONE, - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE - }) => { - $block - })* - _ => Ok(None) - } - } -} -/// Define key pattern in key match statement -#[macro_export] macro_rules! key { - ($code:pat) => { - TuiEvent::Input(crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: $code, - modifiers: crossterm::event::KeyModifiers::NONE, - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE - })) - }; - (Ctrl-$code:pat) => { - TuiEvent::Input(crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: $code, - modifiers: crossterm::event::KeyModifiers::CONTROL, - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE - })) - }; - (Alt-$code:pat) => { - TuiEvent::Input(crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: $code, - modifiers: crossterm::event::KeyModifiers::ALT, - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE - })) - }; - (Shift-$code:pat) => { - TuiEvent::Input(crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: $code, - modifiers: crossterm::event::KeyModifiers::SHIFT, - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE - })) - } -} -pub struct TuiOutput { - pub buffer: Buffer, - pub area: [u16;4], -} +pub struct TuiOutput { pub buffer: Buffer, pub area: [u16;4] } impl Output for TuiOutput { - #[inline] fn area (&self) -> [u16;4] { - self.area - } - #[inline] fn area_mut (&mut self) -> &mut [u16;4] { - &mut self.area - } + #[inline] fn area (&self) -> [u16;4] { self.area } + #[inline] fn area_mut (&mut self) -> &mut [u16;4] { &mut self.area } #[inline] fn render_in (&mut self, area: [u16;4], widget: &dyn Widget @@ -322,14 +240,12 @@ pub enum TuiEvent { // /// JACK notification // Jack(JackEvent) } - impl Area for Rect { fn x (&self) -> u16 { self.x } fn y (&self) -> u16 { self.y } fn w (&self) -> u16 { self.width } fn h (&self) -> u16 { self.height } } - pub fn half_block (lower: bool, upper: bool) -> Option { match (lower, upper) { (true, true) => Some('█'), @@ -338,14 +254,12 @@ pub fn half_block (lower: bool, upper: bool) -> Option { _ => None } } - #[derive(Default)] pub struct BigBuffer { pub width: usize, pub height: usize, pub content: Vec } - impl BigBuffer { pub fn new (width: usize, height: usize) -> Self { Self { width, height, content: vec![Cell::default(); width*height] } @@ -362,7 +276,6 @@ impl BigBuffer { y * self.width + x } } - pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) { for row in 0..area.h() { let y = area.y() + row; @@ -374,7 +287,6 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C } } } - impl Widget for &str { type Engine = Tui; fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> { @@ -399,7 +311,6 @@ impl Widget for String { Ok(to.blit(&self, x, y, None)) } } - impl> Widget for DebugOverlay { type Engine = Tui; fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { @@ -411,7 +322,6 @@ impl> Widget for DebugOverlay { Ok(to.blit(&format!("{w}x{h}+{x}+{y}"), x, y, Some(Style::default().green()))) } } - pub struct Styled>(pub Option