use altui_core::{buffer::Buffer, layout::Rect, widgets::Widget};
use crossterm::event::Event;
use crate::{context::ViewCtx, ctxstore::AreaCache};
#[allow(unused_variables, reason = "Default impls don't use method arguments")]
pub trait View {
type State;
fn logic(&mut self, ctx: &mut ViewCtx, state: &mut Self::State) {}
fn on_event(&mut self, event: Event, ctx: &mut ViewCtx, state: &mut Self::State) {}
fn render(&mut self, area: Rect, cache: &mut AreaCache, buf: &mut Buffer);
}
impl<T> View for Box<T>
where
T: View,
{
type State = T::State;
fn render(&mut self, area: Rect, cache: &mut AreaCache, buf: &mut Buffer) {
self.as_mut().render(area, cache, buf);
}
fn logic(&mut self, ctx: &mut ViewCtx, state: &mut Self::State) {
self.as_mut().logic(ctx, state);
}
fn on_event(&mut self, event: Event, ctx: &mut ViewCtx, state: &mut Self::State) {
self.as_mut().on_event(event, ctx, state);
}
}
pub struct AnyView<State, W> {
logic: Box<dyn Fn(&mut W, &mut ViewCtx, &mut State)>,
widget: W,
phantom: std::marker::PhantomData<State>,
}
impl<State, W> AnyView<State, W>
where
State: 'static,
W: Widget + 'static,
{
pub fn new(widget: W, logic: impl Fn(&mut W, &mut ViewCtx, &mut State) + 'static) -> Self {
AnyView {
logic: Box::new(logic),
widget,
phantom: std::marker::PhantomData,
}
}
pub fn simple(widget: W) -> Self {
let logic: fn(&mut W, &mut ViewCtx, &mut State) = |_, _, _| {};
AnyView {
logic: Box::new(logic),
widget,
phantom: std::marker::PhantomData,
}
}
}
impl<State, W> View for AnyView<State, W>
where
W: Widget,
{
type State = State;
fn logic(&mut self, ctx: &mut ViewCtx, state: &mut State) {
(self.logic)(&mut self.widget, ctx, state)
}
fn on_event(&mut self, _event: Event, _ctx: &mut ViewCtx, _state: &mut State) {}
fn render(&mut self, area: Rect, _: &mut AreaCache, buf: &mut Buffer) {
Widget::render(&mut self.widget, area, buf);
}
}