diff --git a/src/tuine/component/base/shortcut.rs b/src/tuine/component/base/shortcut.rs index 0dd964c8..63fc49e7 100644 --- a/src/tuine/component/base/shortcut.rs +++ b/src/tuine/component/base/shortcut.rs @@ -1,26 +1,77 @@ +use crossterm::event::KeyEvent; +use rustc_hash::FxHashMap; use tui::{backend::Backend, Frame}; -use crate::tuine::{DrawContext, Event, StateContext, Status, TmpComponent}; +use crate::tuine::{ + Bounds, DrawContext, Element, Event, LayoutNode, Size, StateContext, Status, TmpComponent, +}; /// A [`Component`] to handle keyboard shortcuts and assign actions to them. /// /// Inspired by [Flutter's approach](https://docs.flutter.dev/development/ui/advanced/actions_and_shortcuts). -pub struct Shortcut {} +#[derive(Default)] +pub struct Shortcut<'a, Message> { + child: Option>>, + shortcuts: FxHashMap< + Event, + Box< + dyn Fn( + &mut Element<'a, Message>, + &mut StateContext<'_>, + DrawContext<'_>, + Event, + &mut Vec, + ) -> Status, + >, + >, +} -impl TmpComponent for Shortcut { +impl<'a, Message> Shortcut<'a, Message> { + pub fn with_child(child: Element<'a, Message>) -> Self { + Self { + child: Some(child.into()), + shortcuts: Default::default(), + } + } +} + +impl<'a, Message> TmpComponent for Shortcut<'a, Message> { fn draw( - &mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: DrawContext<'_>, - _frame: &mut Frame<'_, B>, + &mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, + frame: &mut Frame<'_, B>, ) where B: Backend, { - todo!() + if let Some(child) = &mut self.child { + if let Some(child_draw_ctx) = draw_ctx.children().next() { + child.draw(state_ctx, child_draw_ctx, frame) + } + } } fn on_event( - &mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: DrawContext<'_>, _event: Event, - _messages: &mut Vec, + &mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event, + messages: &mut Vec, ) -> Status { + if let Some(child_draw_ctx) = draw_ctx.children().next() { + if let Some(child) = &mut self.child { + match child.on_event(state_ctx, child_draw_ctx, event, messages) { + Status::Captured => { + return Status::Captured; + } + Status::Ignored => { + if let Some(f) = self.shortcuts.get(&event) { + return f(child, state_ctx, child_draw_ctx, event, messages); + } + } + } + } + } + Status::Ignored } + + fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size { + todo!() + } } diff --git a/src/tuine/element.rs b/src/tuine/element.rs index 3f30940b..55abed35 100644 --- a/src/tuine/element.rs +++ b/src/tuine/element.rs @@ -13,6 +13,6 @@ pub enum Element<'a, Message> { Carousel, Container(Container<'a, Message>), Flex(Flex<'a, Message>), - Shortcut, + Shortcut(Shortcut<'a, Message>), TextTable(TextTable<'a, Message>), } diff --git a/src/tuine/event.rs b/src/tuine/event.rs index c76aa94d..25d99452 100644 --- a/src/tuine/event.rs +++ b/src/tuine/event.rs @@ -9,7 +9,7 @@ pub enum Status { } /// An [`Event`] represents some sort of user interface event. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Event { /// A keyboard event Keyboard(KeyEvent),