use downcast_rs::{impl_downcast, Downcast};
use std::collections::BTreeMap;
use std::fmt::Debug;
pub mod app;
pub mod component_manager;
pub mod event;
pub mod internal;
pub mod keyboard;
pub mod macros;
pub mod theme;
pub mod tui;
pub use internal::ComponentContext;
use crossterm::event::{KeyEvent, MouseEvent};
use ratatui::{layout::Rect, Frame};
use ratatui::style::{Color, Style}; use tokio::sync::mpsc::UnboundedSender;
use event::Action;
use crate::{event::Event, keyboard::KeyBindings, theme::ThemeManager};
pub type Children = BTreeMap<String, Box<dyn Component>>;
#[derive(Debug)]
pub struct ComponentHandler {
c: Box<dyn Component>,
}
impl ComponentHandler {
pub fn for_(component: Box<dyn Component>) -> Self {
Self { c: component }
}
pub(crate) fn handle_init(&mut self, area: Rect) {
component_manager::init(self.c.as_mut(), area);
}
pub(crate) fn receive_action_handler(&mut self, tx: UnboundedSender<Action>) {
component_manager::receive_action_handler(self.c.as_mut(), tx);
}
pub(crate) fn handle_events(&mut self, event: &Option<Event>) -> Vec<Action> {
component_manager::handle_event_for(self.c.as_mut(), event)
}
pub(crate) fn handle_update(&mut self, action: &Action) {
component_manager::update(self.c.as_mut(), action);
}
pub(crate) fn handle_message(&mut self, message: &str) {
component_manager::handle_message(self.c.as_mut(), message);
}
pub(crate) fn handle_draw(&mut self, f: &mut Frame<'_>) {
component_manager::handle_draw(self.c.as_mut(), f);
}
pub(crate) fn handle_custom_keybindings(&mut self, kb: &mut KeyBindings) {
component_manager::custom_keybindings(self.c.as_mut(), kb);
}
pub(crate) fn handle_theme(&mut self, th: ThemeManager) {
component_manager::handle_theme(self.c.as_mut(), &th);
}
}
pub trait ComponentAccessor: Debug {
fn name(&self) -> String;
fn area(&self) -> Option<Rect>;
fn set_area(&mut self, area: Rect);
fn is_active(&self) -> bool;
fn set_active(&mut self, active: bool);
fn active(&mut self) {
self.set_active(true);
}
fn deactive(&mut self) {
self.set_active(false);
}
fn register_action_handler(&mut self, tx: UnboundedSender<Action>);
fn send(&self, action: &str);
fn send_action(&self, action: Action);
fn get_children(&mut self) -> &mut Children;
fn get_theme_manager(&self) -> &ThemeManager;
fn set_theme_manager(&mut self, theme_manager: ThemeManager);
fn get_color(&self, color_name: &str) -> Color {
self.get_theme_manager()
.get_active_theme()
.map(|theme| theme.get_color(color_name))
.unwrap_or(Color::Reset)
}
fn get_style(&self, style_name: &str) -> Style {
self.get_theme_manager()
.get_active_theme()
.map(|theme| theme.get_style(style_name))
.unwrap_or_default()
}
}
impl_downcast!(Component);
pub trait Component: ComponentAccessor + Downcast {
#[allow(unused)]
fn init(&mut self, area: Rect) {}
fn draw(&mut self, f: &mut Frame<'_>, area: Rect);
fn keybindings(&self) -> KeyBindings {
KeyBindings::default()
}
#[allow(unused_variables)]
fn handle_key_events(&mut self, key: KeyEvent) -> Option<Action> {
None
}
#[allow(unused_variables)]
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Option<Action> {
None
}
#[allow(unused_variables)]
fn handle_tick_event(&mut self) -> Option<Action> {
None
}
#[allow(unused_variables)]
fn handle_frame_event(&mut self) -> Option<Action> {
None
}
#[allow(unused_variables)]
fn handle_paste_event(&mut self, message: &str) -> Option<Action> {
None
}
#[allow(unused_variables)]
fn update(&mut self, action: &Action) {}
#[allow(unused_variables)]
fn on_event(&mut self, message: &str) {}
fn child_mut(&mut self, name: &str) -> Option<&mut Box<dyn Component>> {
self.get_children().get_mut(name)
}
#[allow(clippy::borrowed_box)] fn child(&mut self, name: &str) -> Option<&Box<dyn Component>> {
self.get_children().get(name)
}
#[allow(unused_variables)]
fn on_active_changed(&mut self, active: bool) {}
}