use { std::sync::Arc, std::sync::RwLock, cgmath::{Point2}, crate::{ core::{ View, ViewPort, OuterViewPort, InnerViewPort, Observer, ObserverBroadcast }, sequence::{SequenceView}, terminal::{TerminalStyle, TerminalView, make_label}, projection::ProjectionHelper } }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> pub struct ListDecorator { opening_port: OuterViewPort, closing_port: OuterViewPort, delim_port: OuterViewPort, items: Arc>>, list_style: TerminalStyle, item_style: TerminalStyle, cast: Arc>>>>, proj_helper: ProjectionHelper } impl View for ListDecorator { type Msg = usize; } impl SequenceView for ListDecorator { type Item = OuterViewPort; fn len(&self) -> Option { let l = self.items.len()?; Some(if l == 0 { 2 } else { 2*l + 2 }) } fn get(&self, idx: &usize) -> Option { let item_idx = idx / 2; let list_style = self.list_style.clone(); let item_style = self.item_style.clone(); let l = self.items.len().unwrap_or(0); Some( if *idx == 0 { self.opening_port.clone() .map_item(move |_, atom| atom.add_style_back(list_style)) } else if (l == 0 && *idx == 1) || *idx == 2*l { self.closing_port.clone() .map_item(move |_, atom| atom.add_style_back(list_style)) } else if idx % 2 == 0 { self.delim_port.clone() .map_item(move |_, atom| atom.add_style_back(list_style)) } else { self.items .get(&item_idx)? .map_item(move |_, atom| atom.add_style_back(item_style)) } ) } } impl ListDecorator { pub fn new( opening: &str, closing: &str, delim: &str, level: usize, items_port: OuterViewPort>>, out_port: InnerViewPort>> ) -> Arc> { let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); let li = Arc::new(RwLock::new(ListDecorator { opening_port: make_label(opening), closing_port: make_label(closing), delim_port: make_label(delim), items: proj_helper.new_sequence_arg( items_port, |s: &mut Self, item_idx| { s.cast.notify( &(*item_idx * 2 + 1) ); s.cast.notify( &(*item_idx * 2 + 2) ); } ), list_style: TerminalStyle::fg_color( match level { 0 => (200, 120, 10), 1 => (120, 200, 10), _ => (255, 255, 255) } ), item_style: TerminalStyle::fg_color( match level { _ => (255, 255, 255) } ), cast: out_port.get_broadcast(), proj_helper })); li.write().unwrap().proj_helper.set_proj(&li); out_port.set_view(Some(li.clone())); li } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> use crate::{index::IndexView, grid::GridView}; pub struct VerticalSexprDecorator { opening_port: OuterViewPort, closing_port: OuterViewPort, items: Arc>>, list_style: TerminalStyle, item_style: TerminalStyle, cast: Arc>>>>, proj_helper: ProjectionHelper } impl View for VerticalSexprDecorator { type Msg = Point2; } impl IndexView> for VerticalSexprDecorator { type Item = OuterViewPort; fn area(&self) -> Option>> { let mut area = (0 .. self.items.len()?).map(|i| Point2::new(1 as i16, i as i16)).collect::>(); area.push(Point2::new(0, 0)); area.push(Point2::new(2, self.items.len()? as i16 - 1)); Some(area) } fn get(&self, pt: &Point2) -> Option { let item_idx = pt.y as usize; let list_style = self.list_style.clone(); let item_style = self.item_style.clone(); let l = self.items.len().unwrap_or(0); match pt.x { 0 => { if pt.y == 0 { Some(self.opening_port.clone() .map_item(move |_, atom| atom.add_style_back(list_style))) } else { None } } 1 => { if item_idx < l { Some(self.items.get(&item_idx)?.map_item(move |_, atom| atom.add_style_back(item_style))) } else { None } } 2 => { if (l == 0 && pt.y == 0) || (item_idx+1 == l) { Some(self.closing_port.clone() .map_item(move |_, atom| atom.add_style_back(list_style))) } else { None } } _ => None } } } impl VerticalSexprDecorator { pub fn new( opening: &str, closing: &str, level: usize, items_port: OuterViewPort>>, out_port: InnerViewPort>> ) -> Arc> { let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); let li = Arc::new(RwLock::new(VerticalSexprDecorator { opening_port: make_label(opening), closing_port: make_label(closing), items: proj_helper.new_sequence_arg( items_port, |s: &mut Self, item_idx| { s.cast.notify( &Point2::new(1, *item_idx as i16) ); s.cast.notify( &Point2::new(2, *item_idx as i16 - 1) ); s.cast.notify( &Point2::new(2, *item_idx as i16) ); } ), list_style: TerminalStyle::fg_color( match level { 0 => (200, 120, 10), 1 => (120, 200, 10), _ => (255, 255, 255) } ), item_style: TerminalStyle::fg_color( match level { _ => (255, 255, 255) } ), cast: out_port.get_broadcast(), proj_helper })); li.write().unwrap().proj_helper.set_proj(&li); out_port.set_view(Some(li.clone())); li } } pub trait SExprView { fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort; fn vertical_bar_view(&self, level: usize) -> OuterViewPort; fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort; } impl SExprView for OuterViewPort>> { fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort { let port = ViewPort::new(); ListDecorator::new( "(", ")", " ", level, self.clone(), port.inner() ); port.into_outer() .to_grid_horizontal() .flatten() } fn vertical_bar_view(&self, level: usize) -> OuterViewPort { let port = ViewPort::new(); ListDecorator::new( "Λ", "V", "|", level, self.clone(), port.inner() ); port.into_outer() .to_grid_vertical() .flatten() } fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort { let port = ViewPort::new(); VerticalSexprDecorator::new( "(", ")", level, self.clone(), port.inner() ); port.into_outer() .flatten() } }