bernardo-tui 0.2.7

A keyboard-only, distraction-free TUI widget library
Documentation
use std::fmt::{Debug, Formatter};

use crate::widget::widget::Widget;

pub trait Getter<W>: Fn(&W) -> &dyn Widget {
    fn clone_box(&self) -> Box<dyn Getter<W>>;
}

impl<W, T: Fn(&W) -> &(dyn Widget) + Clone + 'static> Getter<W> for T {
    fn clone_box(&self) -> Box<dyn Getter<W>> {
        Box::new(self.clone())
    }
}

impl<W: 'static> Clone for Box<dyn Getter<W>> {
    fn clone(&self) -> Self {
        (**self).clone_box()
    }
}

pub trait GetterMut<W>: Fn(&mut W) -> &mut dyn Widget {
    fn clone_box(&self) -> Box<dyn GetterMut<W>>;
}

impl<W, T: Fn(&mut W) -> &mut (dyn Widget) + Clone + 'static> GetterMut<W> for T {
    fn clone_box(&self) -> Box<dyn GetterMut<W>> {
        Box::new(self.clone())
    }
}

impl<W: 'static> Clone for Box<dyn GetterMut<W>> {
    fn clone(&self) -> Self {
        (**self).clone_box()
    }
}

pub trait GetterOp<W>: Fn(&W) -> Option<&dyn Widget> {
    fn clone_box(&self) -> Box<dyn GetterOp<W>>;
}

impl<W, T: Fn(&W) -> Option<&(dyn Widget)> + Clone + 'static> GetterOp<W> for T {
    fn clone_box(&self) -> Box<dyn GetterOp<W>> {
        Box::new(self.clone())
    }
}

impl<W: 'static> Clone for Box<dyn GetterOp<W>> {
    fn clone(&self) -> Self {
        (**self).clone_box()
    }
}

pub trait GetterOpMut<W>: Fn(&mut W) -> Option<&mut dyn Widget> {
    fn clone_box(&self) -> Box<dyn GetterOpMut<W>>;
}

impl<W, T: Fn(&mut W) -> Option<&mut (dyn Widget)> + Clone + 'static> GetterOpMut<W> for T {
    fn clone_box(&self) -> Box<dyn GetterOpMut<W>> {
        Box::new(self.clone())
    }
}

impl<W: 'static> Clone for Box<dyn GetterOpMut<W>> {
    fn clone(&self) -> Self {
        (**self).clone_box()
    }
}

pub struct SubwidgetPointer<W: Widget> {
    getter: Box<dyn Getter<W>>,
    getter_mut: Box<dyn GetterMut<W>>,
}

impl<W: Widget> Clone for SubwidgetPointer<W> {
    fn clone(&self) -> Self {
        SubwidgetPointer {
            getter: self.getter.clone_box(),
            getter_mut: self.getter_mut.clone_box(),
        }
    }
}

impl<W: Widget> Debug for SubwidgetPointer<W> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "subwidget_pointer of {}", W::static_typename())
    }
}

impl<W: Widget> SubwidgetPointer<W> {
    pub fn new(getter: Box<dyn Getter<W>>, getter_mut: Box<dyn GetterMut<W>>) -> Self {
        SubwidgetPointer { getter, getter_mut }
    }

    pub fn get<'a>(&self, parent: &'a W) -> &'a dyn Widget {
        (self.getter.clone())(parent)
    }

    pub fn get_mut<'a>(&self, parent: &'a mut W) -> &'a mut dyn Widget {
        (self.getter_mut.clone())(parent)
    }
}

pub struct SubwidgetPointerOp<W: Widget> {
    getter_op: Box<dyn GetterOp<W>>,
    getter_op_mut: Box<dyn GetterOpMut<W>>,
}

impl<W: Widget> Clone for SubwidgetPointerOp<W> {
    fn clone(&self) -> Self {
        SubwidgetPointerOp {
            getter_op: self.getter_op.clone_box(),
            getter_op_mut: self.getter_op_mut.clone_box(),
        }
    }
}

impl<W: Widget> SubwidgetPointerOp<W> {
    pub fn new(getter_op: Box<dyn GetterOp<W>>, getter_op_mut: Box<dyn GetterOpMut<W>>) -> Self {
        SubwidgetPointerOp { getter_op, getter_op_mut }
    }

    pub fn get<'a>(&self, parent: &'a W) -> Option<&'a dyn Widget> {
        (self.getter_op)(parent)
    }

    pub fn get_mut<'a>(&self, parent: &'a mut W) -> Option<&'a mut dyn Widget> {
        (self.getter_op_mut)(parent)
    }
}

#[macro_export]
macro_rules! subwidget {
    ($parent: ident.$ child: ident) => {
        $crate::experiments::subwidget_pointer::SubwidgetPointer::new(
            Box::new(|p: &$parent| &p.$child),
            Box::new(|p: &mut $parent| &mut p.$child),
        )
    };
}

#[macro_export]
macro_rules! todosubwidgetunwrap {
    ($parent: ident.$ child: ident) => {
        $crate::experiments::subwidget_pointer::SubwidgetPointer::new(
            Box::new(|p: &$parent| p.$child.as_ref().unwrap()),
            Box::new(|p: &mut $parent| p.$child.as_mut().unwrap()),
        )
    };
}

#[macro_export]
macro_rules! selfwidget {
    ($parent: ident) => {
        $crate::experiments::subwidget_pointer::SubwidgetPointer::new(
            Box::new(|p: &$parent| p as &dyn Widget),
            Box::new(|p: &mut $parent| p as &mut dyn Widget),
        )
    };
}

#[macro_export]
macro_rules! subwidget_op {
    ($parent: ident.$ child: ident) => {
        $crate::experiments::subwidget_pointer::SubwidgetPointerOp::new(
            Box::new(|p: &$parent| p.$child.as_ref().map(|w| w as &dyn Widget)),
            Box::new(|p: &mut $parent| p.$child.as_mut().map(|w| w as &mut dyn Widget)),
        )
    };
}

#[cfg(test)]
mod tests {
    #![allow(dead_code)]

    use crate::config::theme::Theme;
    use crate::experiments::screenspace::Screenspace;
    use crate::experiments::subwidget_pointer::{SubwidgetPointer, SubwidgetPointerOp};
    use crate::io::input_event::InputEvent;
    use crate::io::output::Output;
    use crate::primitives::xy::XY;
    use crate::widget::any_msg::AnyMsg;
    use crate::widget::widget::{Widget, WID};

    #[test]
    fn test_interface() {
        struct DummySubwidget {}
        impl Widget for DummySubwidget {
            fn id(&self) -> WID {
                unimplemented!()
            }

            fn static_typename() -> &'static str
            where
                Self: Sized,
            {
                unimplemented!()
            }

            fn typename(&self) -> &'static str {
                unimplemented!()
            }

            fn full_size(&self) -> XY {
                unimplemented!()
            }

            fn layout(&mut self, _screenspace: Screenspace) {
                todo!()
            }

            fn on_input(&self, _input_event: InputEvent) -> Option<Box<dyn AnyMsg>> {
                unimplemented!()
            }

            fn update(&mut self, _msg: Box<dyn AnyMsg>) -> Option<Box<dyn AnyMsg>> {
                unimplemented!()
            }

            fn render(&self, _theme: &Theme, _focused: bool, _output: &mut dyn Output) {
                unimplemented!()
            }
        }
        struct DummyWidget {
            subwidget: DummySubwidget,
            self_pointer: SubwidgetPointer<DummyWidget>,

            subwidget_op: Option<DummySubwidget>,
            self_pointer_op: SubwidgetPointerOp<DummyWidget>,
        }
        impl Widget for DummyWidget {
            fn id(&self) -> WID {
                unimplemented!()
            }

            fn static_typename() -> &'static str
            where
                Self: Sized,
            {
                unimplemented!()
            }

            fn typename(&self) -> &'static str {
                unimplemented!()
            }

            fn full_size(&self) -> XY {
                unimplemented!()
            }

            fn layout(&mut self, _screenspace: Screenspace) {
                todo!()
            }

            fn on_input(&self, _input_event: InputEvent) -> Option<Box<dyn AnyMsg>> {
                unimplemented!()
            }

            fn update(&mut self, _msg: Box<dyn AnyMsg>) -> Option<Box<dyn AnyMsg>> {
                unimplemented!()
            }

            fn render(&self, _theme: &Theme, _focused: bool, _output: &mut dyn Output) {
                unimplemented!()
            }
        }

        let _sp = SubwidgetPointer::new(
            Box::new(|dw: &DummyWidget| &dw.subwidget),
            Box::new(|dw: &mut DummyWidget| &mut dw.subwidget),
        );

        let sp3 = subwidget!(DummyWidget.subwidget);

        let _sp4 = sp3.clone();

        impl DummyWidget {
            pub fn new() -> Self {
                DummyWidget {
                    subwidget: DummySubwidget {},
                    self_pointer: subwidget!(DummyWidget.subwidget),
                    subwidget_op: Some(DummySubwidget {}),
                    self_pointer_op: subwidget_op!(DummyWidget.subwidget_op),
                }
            }
        }
    }
}