267 lines
8.7 KiB
Rust
267 lines
8.7 KiB
Rust
use {
|
|
crate::{
|
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
|
projection::ProjectionHelper,
|
|
sequence::SequenceView,
|
|
terminal::{make_label, TerminalStyle, TerminalView},
|
|
},
|
|
cgmath::Point2,
|
|
std::sync::Arc,
|
|
std::sync::RwLock,
|
|
};
|
|
|
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
|
|
pub struct ListDecorator {
|
|
opening_port: OuterViewPort<dyn TerminalView>,
|
|
closing_port: OuterViewPort<dyn TerminalView>,
|
|
delim_port: OuterViewPort<dyn TerminalView>,
|
|
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
|
|
|
list_style: TerminalStyle,
|
|
item_style: TerminalStyle,
|
|
|
|
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>>>,
|
|
proj_helper: ProjectionHelper<Self>,
|
|
}
|
|
|
|
impl View for ListDecorator {
|
|
type Msg = usize;
|
|
}
|
|
|
|
impl SequenceView for ListDecorator {
|
|
type Item = OuterViewPort<dyn TerminalView>;
|
|
|
|
fn len(&self) -> Option<usize> {
|
|
let l = self.items.len()?;
|
|
Some(if l == 0 { 2 } else { 2 * l + 2 })
|
|
}
|
|
|
|
fn get(&self, idx: &usize) -> Option<Self::Item> {
|
|
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<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
|
out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
|
) -> Arc<RwLock<Self>> {
|
|
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
|
|
}
|
|
}
|
|
|
|
pub trait ListDecoration {
|
|
fn decorate(
|
|
&self,
|
|
opening: &str,
|
|
closing: &str,
|
|
delim: &str,
|
|
level: usize,
|
|
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>;
|
|
}
|
|
|
|
impl ListDecoration for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
|
fn decorate(
|
|
&self,
|
|
opening: &str,
|
|
closing: &str,
|
|
delim: &str,
|
|
level: usize,
|
|
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
|
let port = ViewPort::new();
|
|
ListDecorator::new(opening, closing, delim, level, self.clone(), port.inner());
|
|
port.into_outer()
|
|
}
|
|
}
|
|
|
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
|
|
use crate::{grid::GridView, index::IndexView};
|
|
|
|
pub struct VerticalSexprDecorator {
|
|
opening_port: OuterViewPort<dyn TerminalView>,
|
|
closing_port: OuterViewPort<dyn TerminalView>,
|
|
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
|
|
|
list_style: TerminalStyle,
|
|
item_style: TerminalStyle,
|
|
|
|
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>>>,
|
|
proj_helper: ProjectionHelper<Self>,
|
|
}
|
|
|
|
impl View for VerticalSexprDecorator {
|
|
type Msg = Point2<i16>;
|
|
}
|
|
|
|
impl IndexView<Point2<i16>> for VerticalSexprDecorator {
|
|
type Item = OuterViewPort<dyn TerminalView>;
|
|
|
|
fn area(&self) -> Option<Vec<Point2<i16>>> {
|
|
let mut area = (0..self.items.len()?)
|
|
.map(|i| Point2::new(1 as i16, i as i16))
|
|
.collect::<Vec<_>>();
|
|
area.push(Point2::new(0, 0));
|
|
area.push(Point2::new(2, self.items.len()? as i16 - 1));
|
|
Some(area)
|
|
}
|
|
|
|
fn get(&self, pt: &Point2<i16>) -> Option<Self::Item> {
|
|
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<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
|
out_port: InnerViewPort<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>,
|
|
) -> Arc<RwLock<Self>> {
|
|
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<dyn TerminalView>;
|
|
fn vertical_bar_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
|
|
fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
|
|
}
|
|
|
|
impl SExprView for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
|
fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
|
|
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<dyn TerminalView> {
|
|
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<dyn TerminalView> {
|
|
let port = ViewPort::new();
|
|
VerticalSexprDecorator::new("(", ")", level, self.clone(), port.inner());
|
|
port.into_outer().flatten()
|
|
}
|
|
}
|