From eb6dc43e537c49bcdba9d19a90eda2a85fd665be Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Wed, 17 Feb 2021 18:18:39 +0100
Subject: [PATCH] use projection helper in terminal compositor

---
 src/main.rs                | 204 +++++++++++++++++++++++++------------
 src/terminal/compositor.rs | 142 +++++++++-----------------
 2 files changed, 191 insertions(+), 155 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 0a67974..bc5fc5a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,7 +10,7 @@ pub mod terminal;
 pub mod projection;
 pub mod string_editor;
 pub mod leveled_term_view;
-pub mod cell_layout;
+//pub mod cell_layout;
 
 use {
     async_std::{task},
@@ -39,13 +39,69 @@ use {
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+/*
+struct ListView {
+    opening: OuterViewPort<dyn SequenceView<Item = TerminalAtom>>,
+    closing: OuterViewPort<dyn SequenceView<Item = TerminalAtom>>,
+    delim: OuterViewPort<dyn SequenceView<Item = TerminalAtom>>,
+
+    data: Option<Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>>,
+    cast: Arc<RwLock<ObserverBroadcast<>>
+}
+
+impl View for ListView {
+    type Msg = usize;
+}
+
+impl SequenceView for ListView {
+    type Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>;
+
+    fn get(&self, idx: usize) -> Option<Self::Item> {
+        let len = self.data.len();
+
+        if idx == 0 {
+            Some(self.opening.clone())
+        } else if idx < len*2 {
+            if idx % 2 == 1 {
+                self.data.get(idx / 2)
+            } else {
+                Some(self.delim.clone())
+            }
+        } else if idx == len*2 {
+            Some(self.closing.clone())
+        } else {
+            None
+        }
+    }
+}
+
+impl Observer<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>> for ListView {
+    fn reset(&mut self, v: Option<Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>>) {
+        self.data = v;
+    }
+
+    fn notify(&self, idx: usize) {
+        
+    }
+}
+
+impl ListView {
+    fn new(
+        data: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>,
+        port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>
+    ) -> Self {
+        let
+    }
+}
+ */
+
 
 #[async_std::main]
 async fn main() {
     let term_port = ViewPort::<dyn TerminalView>::new();
 
     let mut compositor = TerminalCompositor::new(term_port.inner());
-    compositor.push(ViewPort::<dyn TerminalView>::with_view(Arc::new(ScrambleBackground)).into_outer());
+    //compositor.push(ViewPort::<dyn TerminalView>::with_view(Arc::new(ScrambleBackground)).into_outer());
 
     let mut term = Terminal::new(term_port.outer());
     let term_writer = term.get_writer();
@@ -60,33 +116,10 @@ async fn main() {
         let window_size_port = ViewPort::new();
         let mut window_size = SingletonBuffer::new(Vector2::new(0, 0), window_size_port.inner());
 
-        let opening_port = ViewPort::new();
-        let mut opening = VecBuffer::new(opening_port.inner());
-
-        let delim_port = ViewPort::new();
-        let mut delim = VecBuffer::new(delim_port.inner());
-
-        let closing_port = ViewPort::new();
-        let mut closing = VecBuffer::new(closing_port.inner());
-
-        let e1_port = ViewPort::new();
-        let mut e1 = VecBuffer::new(e1_port.inner());
-
-        let e2_port = ViewPort::new();
-        let mut e2 = VecBuffer::new(e2_port.inner());
-
-        opening.push(TerminalAtom::new('[', TerminalStyle::fg_color((180, 120, 80))));
-        delim.push(TerminalAtom::new(',', TerminalStyle::fg_color((180, 120, 80))));
-        delim.push(TerminalAtom::new(' ', TerminalStyle::fg_color((180, 120, 80))));
-        closing.push(TerminalAtom::new(']', TerminalStyle::fg_color((180, 120, 80))));
-
         let str_list_port = ViewPort::new();
         let mut str_list = VecBuffer::<OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>::new(str_list_port.inner());
 
-        str_list.push(opening_port.outer().to_sequence());
-        str_list.push(closing_port.outer().to_sequence());
-
-        compositor.push(
+        compositor.write().unwrap().push(
             str_list_port.outer()
                 .to_sequence()
                 .flatten()
@@ -99,54 +132,83 @@ async fn main() {
 
         //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
         // welcome message
-        task::sleep(std::time::Duration::from_millis(500)).await;
-        str_list.insert(1, e1_port.outer().to_sequence());
-        for c in "Welcome!".chars() {
-            e1.push(TerminalAtom::new(c, TerminalStyle::fg_color((180, 180, 255))));
+        task::spawn(async move {
+            let opening_port = ViewPort::new();
+            let mut opening = VecBuffer::new(opening_port.inner());
+
+            let delim_port = ViewPort::new();
+            let mut delim = VecBuffer::new(delim_port.inner());
+
+            let closing_port = ViewPort::new();
+            let mut closing = VecBuffer::new(closing_port.inner());
+
+            let e1_port = ViewPort::new();
+            let mut e1 = VecBuffer::new(e1_port.inner());
+
+            let e2_port = ViewPort::new();
+            let mut e2 = VecBuffer::new(e2_port.inner());
+
+            opening.push(TerminalAtom::new('[', TerminalStyle::fg_color((180, 120, 80))));
+            delim.push(TerminalAtom::new(',', TerminalStyle::fg_color((180, 120, 80))));
+            delim.push(TerminalAtom::new(' ', TerminalStyle::fg_color((180, 120, 80))));
+            closing.push(TerminalAtom::new(']', TerminalStyle::fg_color((180, 120, 80))));
+
+            str_list.push(opening_port.outer().to_sequence());
+            str_list.push(closing_port.outer().to_sequence());
+
+            task::sleep(std::time::Duration::from_millis(500)).await;
+            str_list.insert(1, e1_port.outer().to_sequence());
+
+            for c in "Welcome!".chars() {
+                e1.push(TerminalAtom::new(c, TerminalStyle::fg_color((180, 180, 255))));
+                task::sleep(std::time::Duration::from_millis(80)).await;
+            }
+
+            task::sleep(std::time::Duration::from_millis(500)).await;
+            str_list.insert(2, delim_port.outer().to_sequence());
+            str_list.insert(3, e2_port.outer().to_sequence());
             task::sleep(std::time::Duration::from_millis(80)).await;
-        }
-        task::sleep(std::time::Duration::from_millis(500)).await;
-        str_list.insert(2, delim_port.outer().to_sequence());
-        str_list.insert(3, e2_port.outer().to_sequence());
-        task::sleep(std::time::Duration::from_millis(80)).await;
-        for c in "This is a flattened SequenceView.".chars() {
-            e2.push(TerminalAtom::new(c, TerminalStyle::fg_color((180, 180, 255))));
-            task::sleep(std::time::Duration::from_millis(80)).await;
-        }
+            for c in "This is a flattened SequenceView.".chars() {
+                e2.push(TerminalAtom::new(c, TerminalStyle::fg_color((180, 180, 255))));
+                task::sleep(std::time::Duration::from_millis(80)).await;
+            }
 
-        task::sleep(std::time::Duration::from_millis(500)).await;
+            task::sleep(std::time::Duration::from_millis(500)).await;
 
-        let l2_port = ViewPort::new();
-        let mut l2 = VecBuffer::new(l2_port.inner());
+            let l2_port = ViewPort::new();
+            let mut l2 = VecBuffer::new(l2_port.inner());
 
-        *str_list.get_mut(1) = l2_port.outer().to_sequence().flatten();
+            *str_list.get_mut(1) = l2_port.outer().to_sequence().flatten();
 
-        l2.push(opening_port.outer().to_sequence());
+            l2.push(opening_port.outer().to_sequence());
 
-        e1.clear();
-        l2.push(e1_port.outer().to_sequence());
-        l2.push(closing_port.outer().to_sequence());
+            e1.clear();
+            l2.push(e1_port.outer().to_sequence());
+            l2.push(closing_port.outer().to_sequence());
 
-        for c in "they can even be NeStEd!".chars() {
-            e1.push(TerminalAtom::new(c, TerminalStyle::fg_color((180, 180, 255))));
-            task::sleep(std::time::Duration::from_millis(80)).await;
-        }
+            for c in "they can even be NeStEd!".chars() {
+                e1.push(TerminalAtom::new(c, TerminalStyle::fg_color((180, 180, 255))));
+                task::sleep(std::time::Duration::from_millis(80)).await;
+            }
 
-        for i in 0 .. 10 {
-            task::sleep(std::time::Duration::from_millis(100)).await;
+            loop {
+                for i in 0 .. 10 {
+                    task::sleep(std::time::Duration::from_millis(60)).await;
 
-            let col = (100+10*i, 55+20*i, 20+ 20*i);
-            *opening.get_mut(0) = TerminalAtom::new('{', TerminalStyle::fg_color(col));
-            *closing.get_mut(0) = TerminalAtom::new('}', TerminalStyle::fg_color(col));
-        }
+                    let col = (100+10*i, 55+20*i, 20+ 20*i);
+                    *opening.get_mut(0) = TerminalAtom::new('{', TerminalStyle::fg_color(col));
+                    *closing.get_mut(0) = TerminalAtom::new('}', TerminalStyle::fg_color(col));
+                }
 
-        for i in 0 .. 10 {
-            task::sleep(std::time::Duration::from_millis(100)).await;
+                for i in 0 .. 10 {
+                    task::sleep(std::time::Duration::from_millis(60)).await;
 
-            let col = (100+10*i, 55+20*i, 20+ 20*i);
-            *opening.get_mut(0) = TerminalAtom::new('<', TerminalStyle::fg_color(col));
-            *closing.get_mut(0) = TerminalAtom::new('>', TerminalStyle::fg_color(col));
-        }
+                    let col = (100+10*i, 55+20*i, 20+ 20*i);
+                    *opening.get_mut(0) = TerminalAtom::new('<', TerminalStyle::fg_color(col));
+                    *closing.get_mut(0) = TerminalAtom::new('>', TerminalStyle::fg_color(col));
+                }
+            }
+        });
 
         //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
         // string editor 1
@@ -158,6 +220,22 @@ async fn main() {
         let mut editor2 = StringEditor::new();
         let (leveled_edit2_view, leveled_edit2_view_port) = LeveledTermView::new(editor2.insert_view());
 
+        compositor.write().unwrap().push(
+            leveled_edit_view_port
+                .map_key(
+                    |p| p + Vector2::new(1, 1),
+                    |p| Some(p - Vector2::new(1, 1))
+                )
+        );
+
+        compositor.write().unwrap().push(
+            leveled_edit2_view_port
+                .map_key(
+                    |p| p + Vector2::new(1, 2),
+                    |p| Some(p - Vector2::new(1, 2))
+                )
+        );
+        
         
                             /*\
         <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
diff --git a/src/terminal/compositor.rs b/src/terminal/compositor.rs
index a52b153..30eec82 100644
--- a/src/terminal/compositor.rs
+++ b/src/terminal/compositor.rs
@@ -7,68 +7,65 @@ use {
     crate::{
         core::{InnerViewPort, OuterViewPort, Observer, ObserverExt, ObserverBroadcast},
         index::{ImplIndexView},
-        terminal::{TerminalAtom, TerminalView}
+        terminal::{TerminalAtom, TerminalView},
+        projection::ProjectionHelper
     }
 };
 
-struct CompositeLayer {
-    comp: Weak<RwLock<TerminalCompositeView>>,
-    idx: usize
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct TerminalCompositor {
+    layers: Vec<Arc<dyn TerminalView>>,
+    cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
+    proj_helper: ProjectionHelper<Self>
 }
 
-impl Observer<dyn TerminalView> for CompositeLayer {
-    fn reset(&mut self, view: Option<Arc<dyn TerminalView>>) {
-        let comp = self.comp.upgrade().unwrap();
-        let mut c = comp.write().unwrap();
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
 
-        let v = &mut c.layers.get_mut(&self.idx).unwrap().1;
-        let old_view = v.clone();
-        *v = view.clone();
-        drop(v);
-
-        if let Some(old_view) = old_view {
-            if let Some(area) = old_view.area() {
-                c.cast.notify_each(area);
+impl TerminalCompositor {
+    pub fn new(
+        port: InnerViewPort<dyn TerminalView>
+    ) -> Arc<RwLock<Self>> {
+        let comp = Arc::new(RwLock::new(
+            TerminalCompositor {
+                layers: Vec::new(),
+                cast: port.get_broadcast(),
+                proj_helper: ProjectionHelper::new()
             }
-        }
+        ));
 
-        if let Some(view) = view.as_ref() {
-            if let Some(area) = view.area() {
-                c.cast.notify_each(area);
-            }
-        }
+        comp.write().unwrap().proj_helper.set_proj(&comp);
+        port.set_view(Some(comp.clone()));
+
+        comp
     }
 
-    fn notify(&self, pos: &Point2<i16>) {
-        self.comp
-            .upgrade().unwrap()
-            .read().unwrap()
-            .cast.notify(pos);
+    pub fn push(&mut self, v: OuterViewPort<dyn TerminalView>) {
+        self.layers.push(
+            self.proj_helper.new_index_arg(
+                v,
+                |s: &mut Self, pos| {
+                    s.cast.notify(pos);
+                }
+            )
+        );
     }
 }
 
-pub struct TerminalCompositeView {
-    idx_count: usize,
-    layers: HashMap<usize, (Arc<RwLock<CompositeLayer>>, Option<Arc<dyn TerminalView>>)>,
-    cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
-}
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
 
-impl ImplIndexView for TerminalCompositeView {
+impl ImplIndexView for TerminalCompositor {
     type Key = Point2<i16>;
     type Value = TerminalAtom;
 
     fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
         let mut atom = None;
 
-        for idx in 0 .. self.idx_count {
-            if let Some(l) = self.layers.get(&idx) {
-                if let Some(view) = l.1.as_ref() {
-                    match (atom, view.get(pos)) {
-                        (None, next) => atom = next,
-                        (Some(last), Some(next)) => atom = Some(next.add_style_back(last.style)),
-                        _ => {}
-                    }
-                }
+        for layer in self.layers.iter() {
+            match (atom, layer.get(pos)) {
+                (None, next) => atom = next,
+                (Some(last), Some(next)) => atom = Some(next.add_style_back(last.style)),
+                _ => {}
             }
         }
 
@@ -78,19 +75,17 @@ impl ImplIndexView for TerminalCompositeView {
     fn area(&self) -> Option<Vec<Point2<i16>>> {
         let mut area = Some(Vec::new());
 
-        for (_, layer) in self.layers.iter() {
-            if let Some(view) = layer.1.as_ref() {
-                if let (
-                    Some(mut new_area),
-                    Some(area)
-                ) = (
-                    view.area(),
-                    area.as_mut()
-                ) {
-                    area.append(&mut new_area);
-                } else {
-                    area = None;
-                }
+        for layer in self.layers.iter() {
+            if let (
+                Some(mut new_area),
+                Some(area)
+            ) = (
+                layer.area(),
+                area.as_mut()
+            ) {
+                area.append(&mut new_area);
+            } else {
+                area = None;
             }
         }
 
@@ -98,40 +93,3 @@ impl ImplIndexView for TerminalCompositeView {
     }
 }
 
-pub struct TerminalCompositor {
-    view: Arc<RwLock<TerminalCompositeView>>
-}
-
-impl TerminalCompositor {
-    pub fn new(
-        port: InnerViewPort<dyn TerminalView>
-    ) -> Self {
-        let view = Arc::new(RwLock::new(
-            TerminalCompositeView {
-                idx_count: 0,
-                layers: HashMap::new(),
-                cast: port.get_broadcast()
-            }
-        ));
-
-        port.set_view(Some(view.clone()));
-        TerminalCompositor{ view }
-    }
-
-    pub fn push(&mut self, v: OuterViewPort<dyn TerminalView>) {        
-        let mut comp = self.view.write().unwrap();
-        let idx = comp.idx_count;
-        comp.idx_count += 1;
-
-        let layer = Arc::new(RwLock::new(CompositeLayer {
-            comp: Arc::downgrade(&self.view),
-            idx: idx
-        }));
-
-        comp.layers.insert(idx, (layer.clone(), None));
-        drop(comp);
-
-        v.add_observer(layer);
-    }
-}
-