use std::{
any::{Any, TypeId},
fmt,
};
use crate::{
buffer::Buffer,
geometry::{Rect, Vec2},
prelude::MouseEvent,
widgets::layout::LayoutNode,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventResult<M> {
None,
Consumed,
Response(M),
}
impl<M> EventResult<M> {
pub fn is_none(&self) -> bool {
matches!(self, EventResult::None)
}
pub fn or_else<F>(self, f: F) -> Self
where
F: FnOnce() -> Self,
{
if self.is_none() { f() } else { self }
}
}
pub trait Widget<Message: Clone + 'static = ()>: Any {
fn render(&self, buffer: &mut Buffer, layout: &LayoutNode);
fn height(&self, size: &Vec2) -> usize;
fn width(&self, size: &Vec2) -> usize;
fn children(&self) -> Vec<&Element<Message>> {
vec![]
}
fn layout_hash(&self) -> u64 {
0
}
fn layout(&self, node: &mut LayoutNode, area: Rect) {
self.children()
.iter()
.enumerate()
.for_each(|(i, c)| node.children[i].layout(*c, area));
}
fn on_event(
&self,
node: &LayoutNode,
e: &MouseEvent,
) -> EventResult<Message> {
if !node.area.contains_pos(&e.pos) {
return EventResult::None;
}
for (i, child) in self.children().iter().enumerate() {
let m = child.on_event(&node.children[i], e);
if !m.is_none() {
return m;
}
}
EventResult::None
}
}
impl<M> dyn Widget<M> {
pub fn as_any(&self) -> &dyn Any {
self
}
pub fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl<M> fmt::Debug for dyn Widget<M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Converted widget")
}
}
#[derive(Debug)]
pub struct Element<Message: 'static = ()> {
pub type_id: TypeId,
pub widget: Box<dyn Widget<Message>>,
}
impl<Message: Clone + 'static> Element<Message> {
pub fn new<W>(widget: W) -> Self
where
W: Widget<Message> + 'static,
{
Self {
type_id: TypeId::of::<W>(),
widget: Box::new(widget),
}
}
pub fn map<W: Widget<Message> + 'static, F: FnOnce(W) -> W>(
self,
f: F,
) -> Self {
let Element { type_id: _, widget } = self;
let boxed_any: Box<dyn Any> = widget;
match boxed_any.downcast::<W>() {
Ok(bx) => {
let new = f(*bx);
Self {
type_id: TypeId::of::<W>(),
widget: Box::new(new),
}
}
Err(orig) => {
let widget: Box<dyn Widget<Message>> = *orig
.downcast::<Box<dyn Widget<Message>>>()
.expect("Original type must be Box<dyn Widget>");
let type_id = widget.as_ref().type_id();
Self { type_id, widget }
}
}
}
pub fn downcast_ref<W: Widget<Message>>(&self) -> Option<&W> {
self.widget.as_ref().as_any().downcast_ref::<W>()
}
pub fn downcast_mut<W: Widget<Message>>(&mut self) -> Option<&mut W> {
self.widget.as_mut().as_any_mut().downcast_mut::<W>()
}
}
impl<Message: Clone + 'static> Widget<Message> for Element<Message> {
fn render(&self, buffer: &mut Buffer, l: &LayoutNode) {
self.widget.render(buffer, l)
}
fn height(&self, size: &Vec2) -> usize {
self.widget.height(size)
}
fn width(&self, size: &Vec2) -> usize {
self.widget.width(size)
}
fn children(&self) -> Vec<&Element<Message>> {
self.widget.children()
}
fn layout_hash(&self) -> u64 {
self.widget.layout_hash()
}
fn layout(&self, node: &mut LayoutNode, area: Rect) {
self.widget.layout(node, area);
}
fn on_event(
&self,
node: &LayoutNode,
e: &MouseEvent,
) -> EventResult<Message> {
self.widget.on_event(node, e)
}
}