From b86220ae90a54add64976a83a74963011ba4e66d Mon Sep 17 00:00:00 2001
From: Michael Sippel <michael.sippel@mailbox.tu-dresden.de>
Date: Mon, 6 Sep 2021 00:08:36 +0200
Subject: [PATCH 01/16] first color editor

---
 Cargo.toml                   |   1 +
 nested/src/integer/editor.rs |  13 +++-
 sdf_editor/Cargo.toml        |  18 +++++
 sdf_editor/src/main.rs       | 124 +++++++++++++++++++++++++++++++++++
 4 files changed, 155 insertions(+), 1 deletion(-)
 create mode 100644 sdf_editor/Cargo.toml
 create mode 100644 sdf_editor/src/main.rs

diff --git a/Cargo.toml b/Cargo.toml
index c3f151d..30c441b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,7 @@ members = [
     "terminal/display_server",
     "terminal/ansi_parser",
     "shell",
+    "sdf_editor",
     "math/str2int",
     "math/int2str",
     "math/radix_transform",
diff --git a/nested/src/integer/editor.rs b/nested/src/integer/editor.rs
index 0281a94..72d2678 100644
--- a/nested/src/integer/editor.rs
+++ b/nested/src/integer/editor.rs
@@ -6,7 +6,7 @@ use {
     crate::{
         core::{ViewPort, OuterViewPort, Observer},
         singleton::{SingletonView, SingletonBuffer},
-        sequence::{SequenceView},
+        sequence::{SequenceView, SequenceViewExt},
         vec::VecBuffer,
         terminal::{TerminalAtom, TerminalStyle, TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
         tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor},
@@ -102,6 +102,17 @@ impl PosIntEditor {
         self.digits_editor.get_data_port()
             .filter_map(move |digit_editor| digit_editor.read().unwrap().data.get()?.to_digit(radix))
     }
+
+    pub fn get_value(&self) -> u32 {
+        let mut value = 0;
+        let mut weight = 1;
+        for digit_value in self.get_data_port().get_view().unwrap().iter() {
+            value += digit_value * weight;
+            weight *= self.radix;
+        }
+
+        value
+    }
 }
 
 impl TreeNav for PosIntEditor {
diff --git a/sdf_editor/Cargo.toml b/sdf_editor/Cargo.toml
new file mode 100644
index 0000000..44b1df3
--- /dev/null
+++ b/sdf_editor/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "sdf_editor"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+nako = {git= "https://gitlab.com/tendsinmende/nako.git"}
+nako_std = {git= "https://gitlab.com/tendsinmende/nako.git"}
+nakorender = {git="https://gitlab.com/tendsinmende/nako.git", default-features = false}
+nested = { path = "../nested" }
+cgmath = "*"
+termion = "*"
+
+[dependencies.async-std]
+version = "1.9.0"
+features = ["unstable", "attributes"]
diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
new file mode 100644
index 0000000..0823b6d
--- /dev/null
+++ b/sdf_editor/src/main.rs
@@ -0,0 +1,124 @@
+use{
+    std::sync::{Arc, RwLock},
+    cgmath::{Point2, Vector2},
+    termion::event::{Event, Key},
+    nested::{
+        core::{
+            View,
+            ViewPort,
+            Observer,
+            OuterViewPort,
+            port::UpdateTask
+        },
+        singleton::{SingletonBuffer, SingletonView},
+        sequence::{SequenceView},
+        integer::{PosIntEditor},
+        terminal::{Terminal, TerminalCompositor, TerminalEvent, TerminalEditor},
+        list::{ListEditor},
+        tree_nav::{TreeNav}
+    }
+};
+
+
+// projects a Sequence of ints to a color tuple
+struct ColorCollector {
+    src_view: Option<Arc<dyn SequenceView<Item = u32>>>,
+    color: SingletonBuffer<(u8, u8, u8)>
+}
+
+impl ColorCollector {
+    fn update(&mut self) {
+        if let Some(l) = self.src_view.as_ref() {
+            let r = l.get(&0).unwrap_or(0);
+            let g = l.get(&1).unwrap_or(0);
+            let b = l.get(&2).unwrap_or(0);
+
+            self.color.set((r as u8, g as u8, b as u8));
+        }
+    }
+}
+
+impl Observer<dyn SequenceView<Item = u32>> for ColorCollector {
+    fn reset(&mut self, new_view: Option<Arc<dyn SequenceView<Item = u32>>>) {
+        self.src_view = new_view;
+        self.update();
+    }
+
+    fn notify(&mut self, idx: &usize) {
+        self.update();
+    }
+}
+
+
+#[async_std::main]
+async fn main() {
+    let term_port = ViewPort::new();
+    let compositor = TerminalCompositor::new(term_port.inner());
+
+    let mut term = Terminal::new(term_port.outer());
+    let term_writer = term.get_writer();
+
+    let mut color_editor = ListEditor::new(
+        || {
+            Arc::new(RwLock::new(PosIntEditor::new(16)))
+        },
+        nested::list::ListEditorStyle::Clist
+    );
+
+    color_editor.goto(nested::tree_nav::TreeCursor {
+        leaf_mode: nested::list::ListCursorMode::Insert,
+        tree_addr: vec![ 0 ]
+    });
+
+    let color_port = ViewPort::new();
+    let color_collector = Arc::new(RwLock::new(ColorCollector {
+        src_view: None,
+        color: SingletonBuffer::new((0, 0, 0), color_port.inner())
+    }));
+
+    color_editor.get_data_port().map(
+        |sub_editor| sub_editor.read().unwrap().get_value()
+    ).add_observer(
+        color_collector
+    );
+
+    compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(2, 2)));
+    
+    async_std::task::spawn(
+        async move {
+            loop {
+                term_port.update();
+                match term.next_event().await {
+                    TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
+                    TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
+                    TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
+
+                    TerminalEvent::Input(Event::Key(Key::Left)) => {
+                        color_editor.pxev();
+                    }
+                    TerminalEvent::Input(Event::Key(Key::Right)) => {
+                        color_editor.nexd();
+                    }
+                    TerminalEvent::Input(Event::Key(Key::Up)) => {
+                        color_editor.up();
+                    }
+                    TerminalEvent::Input(Event::Key(Key::Down)) => {
+                        color_editor.dn();
+                    }
+                    TerminalEvent::Input(Event::Key(Key::Home)) => {
+                        color_editor.goto_home();
+                    }
+                    TerminalEvent::Input(Event::Key(Key::End)) => {
+                        color_editor.goto_end();
+                    }
+                    event => {
+                        color_editor.handle_terminal_event(&event);
+                    }
+                }
+            }
+        }
+    );
+    
+    term_writer.show().await.expect("output error!");
+}
+

From 4ce574ea78532fb1c36d7019eddd49246ae6a84e Mon Sep 17 00:00:00 2001
From: Tendsin Mende <tendsin@protonmail.com>
Date: Mon, 6 Sep 2021 00:56:51 +0200
Subject: [PATCH 02/16] initial sdf output

---
 sdf_editor/src/main.rs | 82 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 3 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 0823b6d..63b15e2 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -16,7 +16,16 @@ use{
         terminal::{Terminal, TerminalCompositor, TerminalEvent, TerminalEditor},
         list::{ListEditor},
         tree_nav::{TreeNav}
-    }
+    },
+    nako::{
+        stream::{SecondaryStream2d, PrimaryStream2d},
+        glam::{Vec2, Vec3},
+        operations::{
+            planar::primitives2d::Box2d,
+            volumetric::{Color, Union, Round},
+        },
+    },
+    nakorender::{backend::{Backend, LayerInfo}, winit, camera::Camera2d}
 };
 
 
@@ -32,7 +41,7 @@ impl ColorCollector {
             let r = l.get(&0).unwrap_or(0);
             let g = l.get(&1).unwrap_or(0);
             let b = l.get(&2).unwrap_or(0);
-
+            println!("Set r: {}", r);
             self.color.set((r as u8, g as u8, b as u8));
         }
     }
@@ -83,11 +92,14 @@ async fn main() {
     );
 
     compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(2, 2)));
+
+    let color_view = color_port.outer().get_view();
     
     async_std::task::spawn(
         async move {
             loop {
                 term_port.update();
+                color_port.update();
                 match term.next_event().await {
                     TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
@@ -118,7 +130,71 @@ async fn main() {
             }
         }
     );
+
+    async_std::task::spawn(async move {
+        term_writer.show().await.expect("output error!");
+    });
+
+
+    let event_loop = nakorender::winit::event_loop::EventLoop::new();
+    let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
+    let mut renderer = nakorender::marp::MarpBackend::new(&window, &event_loop);
+
+    let id = renderer.new_layer_2d();
+    renderer.set_layer_order(&[id.into()]);
+    renderer.update_camera_2d(id, Camera2d{
+        extent: Vec2::new(2.0, 2.0),
+        location: Vec2::new(-1.0, -1.0),
+        rotation: 0.0
+    });
     
-    term_writer.show().await.expect("output error!");
+    event_loop.run(move |event, _target, control_flow|{
+        //Set to polling for now, might be overwritten
+        //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderers don't work that hard
+        //if nothing changes. So should be okay for a alpha style programm.
+        *control_flow = winit::event_loop::ControlFlow::Poll;
+        
+
+        
+        //now check if a rerender was requested, or if we worked on all
+        //events on that batch
+        match event{
+            winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::Resized(newsize)} => {
+                //update layer to cover whole window again.
+                renderer.set_layer_info(id.into(), LayerInfo{
+                    extent: (newsize.width as usize, newsize.height as usize),
+                    location: (0,0)
+                });
+            }
+            winit::event::Event::MainEventsCleared => {
+                window.request_redraw();
+            }
+            winit::event::Event::RedrawRequested(_) => {
+                let new_sdf = sdf_from_color(color_view.get());
+                renderer.update_sdf_2d(id, new_sdf);
+
+                renderer.render(&window);
+            }
+            _ => {},
+        }
+        
+    })
 }
 
+
+
+fn sdf_from_color(c: (u8, u8, u8)) -> PrimaryStream2d{
+    PrimaryStream2d::new()
+        .push(
+            SecondaryStream2d::new(
+                Union,
+                Box2d{extent: Vec2::new(0.5, 0.5)}
+            ).push_mod(Color(
+                Vec3::new(
+                    (c.0 as f32 / 255.0).clamp(0.0, 1.0),
+                    (c.1 as f32 / 255.0).clamp(0.0, 1.0),
+                    (c.2 as f32 / 255.0).clamp(0.0, 1.0),
+                )
+            )).push_mod(Round{radius: 0.2}).build()
+            ).build()
+}

From 859a3f12ff06e775697c32c949dd2fda0966fd31 Mon Sep 17 00:00:00 2001
From: Michael Sippel <michael.sippel@mailbox.tu-dresden.de>
Date: Mon, 6 Sep 2021 01:22:08 +0200
Subject: [PATCH 03/16] fix color update

---
 sdf_editor/src/main.rs | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 63b15e2..d42912c 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -7,6 +7,7 @@ use{
             View,
             ViewPort,
             Observer,
+            ObserverExt,
             OuterViewPort,
             port::UpdateTask
         },
@@ -41,7 +42,7 @@ impl ColorCollector {
             let r = l.get(&0).unwrap_or(0);
             let g = l.get(&1).unwrap_or(0);
             let b = l.get(&2).unwrap_or(0);
-            println!("Set r: {}", r);
+
             self.color.set((r as u8, g as u8, b as u8));
         }
     }
@@ -82,13 +83,15 @@ async fn main() {
     let color_port = ViewPort::new();
     let color_collector = Arc::new(RwLock::new(ColorCollector {
         src_view: None,
-        color: SingletonBuffer::new((0, 0, 0), color_port.inner())
+        color: SingletonBuffer::new((200, 200, 0), color_port.inner())
     }));
 
-    color_editor.get_data_port().map(
+    let col_seq_port = color_editor.get_data_port().map(
         |sub_editor| sub_editor.read().unwrap().get_value()
-    ).add_observer(
-        color_collector
+    );
+    color_port.add_update_hook(Arc::new(col_seq_port.0.clone()));
+    col_seq_port.add_observer(
+        color_collector.clone()
     );
 
     compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(2, 2)));
@@ -98,9 +101,16 @@ async fn main() {
     async_std::task::spawn(
         async move {
             loop {
-                term_port.update();
                 color_port.update();
+                term_port.update();
                 match term.next_event().await {
+                    TerminalEvent::Resize(new_size) => {
+                        term_port.inner().get_broadcast().notify_each(
+                            nested::grid::GridWindowIterator::from(
+                                Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
+                            )
+                        );
+                    }
                     TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,

From d647e45c26b4ae40a44d3fc37df845632451def2 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Thu, 9 Sep 2021 18:18:48 +0200
Subject: [PATCH 04/16] sdfs: convert TerminalAtom to SDF

---
 sdf_editor/src/main.rs | 137 +++++++++++++++++++++++++++++++++--------
 1 file changed, 111 insertions(+), 26 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index d42912c..533412f 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -14,7 +14,7 @@ use{
         singleton::{SingletonBuffer, SingletonView},
         sequence::{SequenceView},
         integer::{PosIntEditor},
-        terminal::{Terminal, TerminalCompositor, TerminalEvent, TerminalEditor},
+        terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalCompositor, TerminalEvent, TerminalEditor},
         list::{ListEditor},
         tree_nav::{TreeNav}
     },
@@ -26,10 +26,18 @@ use{
             volumetric::{Color, Union, Round},
         },
     },
-    nakorender::{backend::{Backend, LayerInfo}, winit, camera::Camera2d}
+    nakorender::{
+        backend::{Backend, LayerId, LayerId2d, LayerInfo},
+        marp::MarpBackend,
+        winit, camera::Camera2d
+    },
+    nako_std::{
+        text::Character
+    },
+    std::{fs::File, io::Read, mem::needs_drop, path::Path},
+    font_kit::font::Font,
 };
 
-
 // projects a Sequence of ints to a color tuple
 struct ColorCollector {
     src_view: Option<Arc<dyn SequenceView<Item = u32>>>,
@@ -60,6 +68,64 @@ impl Observer<dyn SequenceView<Item = u32>> for ColorCollector {
 }
 
 
+struct TermAtomSDF {
+    atom: TerminalAtom
+}
+
+impl TermAtomSDF {
+    fn new(atom: TerminalAtom) -> Self {
+        TermAtomSDF {
+            atom
+        }
+    }
+
+    fn update_bg(&self, layer_id: LayerId2d, renderer: &mut MarpBackend) {
+        let (r,g,b) = self.atom.style.bg_color.unwrap_or((0, 0, 0));
+       
+        let stream = PrimaryStream2d::new()
+            .push(
+                SecondaryStream2d::new(
+                    Union,
+                    Box2d {
+                        extent: Vec2::new(0.5, 1.0)
+                    }
+                ).push_mod(
+                    Color(
+                        Vec3::new(
+                            (r as f32 / 255.0).clamp(0.0, 1.0),
+                            (g as f32 / 255.0).clamp(0.0, 1.0),
+                            (b as f32 / 255.0).clamp(0.0, 1.0),
+                        )
+                    )
+                ).build()
+            ).build();
+
+        renderer.update_sdf_2d(layer_id, stream);
+    }
+
+    fn update_ch(&self, layer_id: LayerId2d, renderer: &mut MarpBackend) {
+        if let Some(c) = self.atom.c {
+            let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Light.ttf"),0).unwrap();
+            let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.2);
+
+            let (r,g,b) = self.atom.style.fg_color.unwrap_or((0, 0, 0));
+
+            ch.color = Vec3::new(
+                (r as f32 / 255.0).clamp(0.0, 1.0),
+                (g as f32 / 255.0).clamp(0.0, 1.0),
+                (b as f32 / 255.0).clamp(0.0, 1.0),
+            );
+
+            let mut stream = PrimaryStream2d::new();
+            stream = ch.record_character(stream);
+            renderer.update_sdf_2d(layer_id, stream.build());
+        } else {
+            renderer.update_sdf_2d(layer_id, PrimaryStream2d::new().build());
+        }
+    }
+}
+
+
 #[async_std::main]
 async fn main() {
     let term_port = ViewPort::new();
@@ -126,6 +192,7 @@ async fn main() {
                     }
                     TerminalEvent::Input(Event::Key(Key::Down)) => {
                         color_editor.dn();
+                        color_editor.goto_home();
                     }
                     TerminalEvent::Input(Event::Key(Key::Home)) => {
                         color_editor.goto_home();
@@ -144,20 +211,31 @@ async fn main() {
     async_std::task::spawn(async move {
         term_writer.show().await.expect("output error!");
     });
-
-
+    
     let event_loop = nakorender::winit::event_loop::EventLoop::new();
     let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
     let mut renderer = nakorender::marp::MarpBackend::new(&window, &event_loop);
 
-    let id = renderer.new_layer_2d();
-    renderer.set_layer_order(&[id.into()]);
-    renderer.update_camera_2d(id, Camera2d{
-        extent: Vec2::new(2.0, 2.0),
-        location: Vec2::new(-1.0, -1.0),
+    let bg_id = renderer.new_layer_2d();
+    renderer.update_camera_2d(bg_id, Camera2d{
+        extent: Vec2::new(10.0, 10.0),
+        location: Vec2::new(0.0, 0.0),
         rotation: 0.0
     });
-    
+
+    let ch_id = renderer.new_layer_2d();
+    renderer.update_camera_2d(ch_id, Camera2d{
+        extent: Vec2::new(10.0, 10.0),
+        location: Vec2::new(0.0, 0.0),
+        rotation: 0.0
+    });
+
+    renderer.set_layer_order(&[bg_id.into(), ch_id.into()]);
+
+    let asdf = TermAtomSDF::new(TerminalAtom::new('H', TerminalStyle::fg_color((98, 200, 60)).add(TerminalStyle::bg_color((40,40,40)))));
+    asdf.update_bg(bg_id, &mut renderer);
+    asdf.update_ch(ch_id, &mut renderer);
+
     event_loop.run(move |event, _target, control_flow|{
         //Set to polling for now, might be overwritten
         //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderers don't work that hard
@@ -171,7 +249,12 @@ async fn main() {
         match event{
             winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::Resized(newsize)} => {
                 //update layer to cover whole window again.
-                renderer.set_layer_info(id.into(), LayerInfo{
+                renderer.set_layer_info(bg_id.into(), LayerInfo{
+                    extent: (newsize.width as usize, newsize.height as usize),
+                    location: (0,0)
+                });
+
+                renderer.set_layer_info(ch_id.into(), LayerInfo{
                     extent: (newsize.width as usize, newsize.height as usize),
                     location: (0,0)
                 });
@@ -179,10 +262,7 @@ async fn main() {
             winit::event::Event::MainEventsCleared => {
                 window.request_redraw();
             }
-            winit::event::Event::RedrawRequested(_) => {
-                let new_sdf = sdf_from_color(color_view.get());
-                renderer.update_sdf_2d(id, new_sdf);
-
+            winit::event::Event::RedrawRequested(_) => {                
                 renderer.render(&window);
             }
             _ => {},
@@ -191,20 +271,25 @@ async fn main() {
     })
 }
 
-
-
-fn sdf_from_color(c: (u8, u8, u8)) -> PrimaryStream2d{
+fn sdf_from_color(c: (u8, u8, u8)) -> PrimaryStream2d {
     PrimaryStream2d::new()
         .push(
             SecondaryStream2d::new(
                 Union,
-                Box2d{extent: Vec2::new(0.5, 0.5)}
-            ).push_mod(Color(
-                Vec3::new(
-                    (c.0 as f32 / 255.0).clamp(0.0, 1.0),
-                    (c.1 as f32 / 255.0).clamp(0.0, 1.0),
-                    (c.2 as f32 / 255.0).clamp(0.0, 1.0),
+                Box2d {
+                    extent: Vec2::new(0.5, 0.5)
+                }
+            ).push_mod(
+                Color(
+                    Vec3::new(
+                        (c.0 as f32 / 255.0).clamp(0.0, 1.0),
+                        (c.1 as f32 / 255.0).clamp(0.0, 1.0),
+                        (c.2 as f32 / 255.0).clamp(0.0, 1.0),
+                    )
                 )
-            )).push_mod(Round{radius: 0.2}).build()
+            ).push_mod(
+                Round{radius: 0.2}
             ).build()
+        ).build()
 }
+

From eb2f4c28dd68efa22ffd7944e3251ec9c8cd6b76 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 01:04:00 +0200
Subject: [PATCH 05/16] initial terminal view rendering with sdfs

still very whacky
---
 sdf_editor/src/main.rs | 223 ++++++++++++++++++++++++++---------------
 1 file changed, 144 insertions(+), 79 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 533412f..cc62e4d 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -1,5 +1,8 @@
 use{
-    std::sync::{Arc, RwLock},
+    std::{
+        sync::{Arc, RwLock, Mutex},
+        collections::HashMap
+    },
     cgmath::{Point2, Vector2},
     termion::event::{Event, Key},
     nested::{
@@ -14,7 +17,7 @@ use{
         singleton::{SingletonBuffer, SingletonView},
         sequence::{SequenceView},
         integer::{PosIntEditor},
-        terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalCompositor, TerminalEvent, TerminalEditor},
+        terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalView, TerminalCompositor, TerminalEvent, TerminalEditor},
         list::{ListEditor},
         tree_nav::{TreeNav}
     },
@@ -80,14 +83,15 @@ impl TermAtomSDF {
     }
 
     fn update_bg(&self, layer_id: LayerId2d, renderer: &mut MarpBackend) {
-        let (r,g,b) = self.atom.style.bg_color.unwrap_or((0, 0, 0));
-       
-        let stream = PrimaryStream2d::new()
-            .push(
+        let mut stream = PrimaryStream2d::new();
+
+        let (r,g,b) = self.atom.style.bg_color.unwrap_or((0,0,0));
+
+            stream = stream.push(
                 SecondaryStream2d::new(
                     Union,
                     Box2d {
-                        extent: Vec2::new(0.5, 1.0)
+                        extent: Vec2::new(0.6, 1.0)
                     }
                 ).push_mod(
                     Color(
@@ -98,15 +102,17 @@ impl TermAtomSDF {
                         )
                     )
                 ).build()
-            ).build();
+            );
 
-        renderer.update_sdf_2d(layer_id, stream);
+        renderer.update_sdf_2d(layer_id, stream.build());
     }
 
     fn update_ch(&self, layer_id: LayerId2d, renderer: &mut MarpBackend) {
+        let mut stream = PrimaryStream2d::new();
+        
         if let Some(c) = self.atom.c {
             let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Light.ttf"),0).unwrap();
-            let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.2);
+            let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.01);
 
             let (r,g,b) = self.atom.style.fg_color.unwrap_or((0, 0, 0));
 
@@ -116,16 +122,108 @@ impl TermAtomSDF {
                 (b as f32 / 255.0).clamp(0.0, 1.0),
             );
 
-            let mut stream = PrimaryStream2d::new();
             stream = ch.record_character(stream);
-            renderer.update_sdf_2d(layer_id, stream.build());
-        } else {
-            renderer.update_sdf_2d(layer_id, PrimaryStream2d::new().build());
         }
+
+        renderer.update_sdf_2d(layer_id, stream.build());
     }
 }
 
+struct SdfTerm {
+    src_view: Arc<dyn TerminalView>,
+    bg_layers: HashMap<Point2<i16>, LayerId2d>,
+    ch_layers: HashMap<Point2<i16>, LayerId2d>,
+    renderer: Arc<Mutex<MarpBackend>>
+}
 
+impl SdfTerm {
+    fn update_order(&mut self) {
+        self.renderer.lock().unwrap().set_layer_order(
+                vec![
+                    self.bg_layers.iter().filter(
+                        |(pt, _)|
+                        if let Some(a) = self.src_view.get(pt) {
+                            a.style.bg_color.is_some()
+                        } else {
+                            false
+                        }
+                    )
+                        .collect::<Vec<_>>()
+                        .into_iter(),
+                    self.ch_layers.iter().filter(
+                        |(pt, _)|
+                        if let Some(a) = self.src_view.get(pt) {
+                            a.c.is_some()
+                        } else {
+                            false
+                        }
+                    )
+                        .collect::<Vec<_>>()
+                        .into_iter()
+                ]
+                .into_iter()
+                .flatten()
+                .map(|(_,id)| (*id).into())
+                .collect::<Vec<_>>()
+                .as_slice()
+        );
+    }
+
+    fn update(&mut self, pt: &Point2<i16>) {
+        if self.bg_layers.get(pt).is_none() {
+            let id = self.renderer.lock().unwrap().new_layer_2d();
+
+            self.renderer.lock().unwrap().update_camera_2d(
+                id.into(),
+                Camera2d {
+                    extent: Vec2::new(0.5, 1.0),
+                    location: Vec2::new(0.0, 0.0),
+                    rotation: 0.0
+                });
+            self.renderer.lock().unwrap().set_layer_info(
+                id.into(),
+                LayerInfo {
+                    extent: (60, 100),
+                    location: (pt.x as usize * 60, pt.y as usize * 100)
+                });
+
+            self.bg_layers.insert(*pt, id);
+        }
+        if self.ch_layers.get(pt).is_none() {
+            let id = self.renderer.lock().unwrap().new_layer_2d();
+
+            self.renderer.lock().unwrap().update_camera_2d(
+                id.into(),
+                Camera2d {
+                    extent: Vec2::new(0.5, 1.0),
+                    location: Vec2::new(0.0, 0.0),
+                    rotation: 0.0
+                });
+            self.renderer.lock().unwrap().set_layer_info(
+                id.into(),
+                LayerInfo {
+                    extent: (60, 100),
+                    location: (pt.x as usize * 60, pt.y as usize * 100)
+                });
+
+            self.ch_layers.insert(*pt, id);
+        }
+
+        if let Some(atom) = self.src_view.get(pt) {
+            let atom_stream_builder = TermAtomSDF::new(atom);
+            atom_stream_builder.update_bg(*self.bg_layers.get(pt).unwrap(), &mut *self.renderer.lock().unwrap());
+            atom_stream_builder.update_ch(*self.ch_layers.get(pt).unwrap(), &mut *self.renderer.lock().unwrap());
+        }
+    }
+}
+/*
+impl Observer<dyn TerminalView> for SdfTerm {
+    fn notify(&mut self, pt: &Point2<i16>) {
+        self.update(pt);
+        self.update_order();
+    }
+}
+*/
 #[async_std::main]
 async fn main() {
     let term_port = ViewPort::new();
@@ -163,19 +261,37 @@ async fn main() {
     compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(2, 2)));
 
     let color_view = color_port.outer().get_view();
-    
+
+    let cp = color_port.clone();
+    let tp = term_port.clone();
+
+    let event_loop = nakorender::winit::event_loop::EventLoop::new();
+    let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
+    let mut renderer = Arc::new(Mutex::new(nakorender::marp::MarpBackend::new(&window, &event_loop)));
+
+    let mut sdf_term = Arc::new(RwLock::new(SdfTerm {
+        src_view: term_port.outer().get_view().unwrap(),
+        bg_layers: HashMap::new(),
+        ch_layers: HashMap::new(),
+        renderer: renderer.clone()
+    }));
+    //term_port.outer().add_observer(sdf_term.clone());
+
     async_std::task::spawn(
         async move {
             loop {
-                color_port.update();
-                term_port.update();
+                cp.update();
+                tp.update();
+                
                 match term.next_event().await {
                     TerminalEvent::Resize(new_size) => {
-                        term_port.inner().get_broadcast().notify_each(
+                        tp.inner().get_broadcast().notify_each(
                             nested::grid::GridWindowIterator::from(
                                 Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
                             )
                         );
+
+                        
                     }
                     TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
@@ -211,59 +327,30 @@ async fn main() {
     async_std::task::spawn(async move {
         term_writer.show().await.expect("output error!");
     });
-    
-    let event_loop = nakorender::winit::event_loop::EventLoop::new();
-    let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
-    let mut renderer = nakorender::marp::MarpBackend::new(&window, &event_loop);
-
-    let bg_id = renderer.new_layer_2d();
-    renderer.update_camera_2d(bg_id, Camera2d{
-        extent: Vec2::new(10.0, 10.0),
-        location: Vec2::new(0.0, 0.0),
-        rotation: 0.0
-    });
-
-    let ch_id = renderer.new_layer_2d();
-    renderer.update_camera_2d(ch_id, Camera2d{
-        extent: Vec2::new(10.0, 10.0),
-        location: Vec2::new(0.0, 0.0),
-        rotation: 0.0
-    });
-
-    renderer.set_layer_order(&[bg_id.into(), ch_id.into()]);
-
-    let asdf = TermAtomSDF::new(TerminalAtom::new('H', TerminalStyle::fg_color((98, 200, 60)).add(TerminalStyle::bg_color((40,40,40)))));
-    asdf.update_bg(bg_id, &mut renderer);
-    asdf.update_ch(ch_id, &mut renderer);
 
     event_loop.run(move |event, _target, control_flow|{
         //Set to polling for now, might be overwritten
-        //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderers don't work that hard
+        //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderer.lock().unwrap()s don't work that hard
         //if nothing changes. So should be okay for a alpha style programm.
         *control_flow = winit::event_loop::ControlFlow::Poll;
         
-
-        
         //now check if a rerender was requested, or if we worked on all
         //events on that batch
         match event{
             winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::Resized(newsize)} => {
-                //update layer to cover whole window again.
-                renderer.set_layer_info(bg_id.into(), LayerInfo{
-                    extent: (newsize.width as usize, newsize.height as usize),
-                    location: (0,0)
-                });
-
-                renderer.set_layer_info(ch_id.into(), LayerInfo{
-                    extent: (newsize.width as usize, newsize.height as usize),
-                    location: (0,0)
-                });
             }
             winit::event::Event::MainEventsCleared => {
                 window.request_redraw();
             }
-            winit::event::Event::RedrawRequested(_) => {                
-                renderer.render(&window);
+            winit::event::Event::RedrawRequested(_) => {
+                for pt in nested::grid::GridWindowIterator::from(
+                    Point2::new(0, 0) .. Point2::new(10, 4)
+                ) {
+                    sdf_term.write().unwrap().update(&pt);
+                }
+                sdf_term.write().unwrap().update_order();
+
+                renderer.lock().unwrap().render(&window);
             }
             _ => {},
         }
@@ -271,25 +358,3 @@ async fn main() {
     })
 }
 
-fn sdf_from_color(c: (u8, u8, u8)) -> PrimaryStream2d {
-    PrimaryStream2d::new()
-        .push(
-            SecondaryStream2d::new(
-                Union,
-                Box2d {
-                    extent: Vec2::new(0.5, 0.5)
-                }
-            ).push_mod(
-                Color(
-                    Vec3::new(
-                        (c.0 as f32 / 255.0).clamp(0.0, 1.0),
-                        (c.1 as f32 / 255.0).clamp(0.0, 1.0),
-                        (c.2 as f32 / 255.0).clamp(0.0, 1.0),
-                    )
-                )
-            ).push_mod(
-                Round{radius: 0.2}
-            ).build()
-        ).build()
-}
-

From ebada704c0886713cd2ee9418a3aa90b7105a2a4 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 01:59:42 +0200
Subject: [PATCH 06/16] preview color in nako window

---
 sdf_editor/src/main.rs | 121 +++++++++++++++++++++++++++--------------
 1 file changed, 81 insertions(+), 40 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index cc62e4d..7881208 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -111,7 +111,7 @@ impl TermAtomSDF {
         let mut stream = PrimaryStream2d::new();
         
         if let Some(c) = self.atom.c {
-            let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Light.ttf"),0).unwrap();
+            let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap();
             let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.01);
 
             let (r,g,b) = self.atom.style.fg_color.unwrap_or((0, 0, 0));
@@ -131,42 +131,29 @@ impl TermAtomSDF {
 
 struct SdfTerm {
     src_view: Arc<dyn TerminalView>,
-    bg_layers: HashMap<Point2<i16>, LayerId2d>,
-    ch_layers: HashMap<Point2<i16>, LayerId2d>,
+    bg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
+    ch_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
     renderer: Arc<Mutex<MarpBackend>>
 }
 
 impl SdfTerm {
-    fn update_order(&mut self) {
-        self.renderer.lock().unwrap().set_layer_order(
-                vec![
-                    self.bg_layers.iter().filter(
-                        |(pt, _)|
-                        if let Some(a) = self.src_view.get(pt) {
-                            a.style.bg_color.is_some()
-                        } else {
-                            false
-                        }
-                    )
-                        .collect::<Vec<_>>()
-                        .into_iter(),
-                    self.ch_layers.iter().filter(
-                        |(pt, _)|
-                        if let Some(a) = self.src_view.get(pt) {
-                            a.c.is_some()
-                        } else {
-                            false
-                        }
-                    )
-                        .collect::<Vec<_>>()
-                        .into_iter()
-                ]
-                .into_iter()
-                .flatten()
-                .map(|(_,id)| (*id).into())
+    fn get_order(&mut self) -> Vec<LayerId> {
+        vec![
+            self.bg_layers.iter().filter(
+                |(_pt, (active, _id))| *active
+            )
                 .collect::<Vec<_>>()
-                .as_slice()
-        );
+                .into_iter(),
+            self.ch_layers.iter().filter(
+                |(_pt, (active, _id))| *active
+            )
+                .collect::<Vec<_>>()
+                .into_iter()
+        ]
+            .into_iter()
+            .flatten()
+            .map(|(_,(_,id))| (*id).into())
+            .collect::<Vec<_>>()
     }
 
     fn update(&mut self, pt: &Point2<i16>) {
@@ -187,7 +174,7 @@ impl SdfTerm {
                     location: (pt.x as usize * 60, pt.y as usize * 100)
                 });
 
-            self.bg_layers.insert(*pt, id);
+            self.bg_layers.insert(*pt, (false, id));
         }
         if self.ch_layers.get(pt).is_none() {
             let id = self.renderer.lock().unwrap().new_layer_2d();
@@ -206,13 +193,22 @@ impl SdfTerm {
                     location: (pt.x as usize * 60, pt.y as usize * 100)
                 });
 
-            self.ch_layers.insert(*pt, id);
+            self.ch_layers.insert(*pt, (false, id));
         }
 
         if let Some(atom) = self.src_view.get(pt) {
             let atom_stream_builder = TermAtomSDF::new(atom);
-            atom_stream_builder.update_bg(*self.bg_layers.get(pt).unwrap(), &mut *self.renderer.lock().unwrap());
-            atom_stream_builder.update_ch(*self.ch_layers.get(pt).unwrap(), &mut *self.renderer.lock().unwrap());
+            atom_stream_builder.update_bg(self.bg_layers.get(pt).unwrap().1, &mut *self.renderer.lock().unwrap());
+            atom_stream_builder.update_ch(self.ch_layers.get(pt).unwrap().1, &mut *self.renderer.lock().unwrap());
+
+            let has_bg = atom.style.bg_color.is_some();
+            let has_fg = atom.c.unwrap_or(' ') != ' ';
+
+            self.bg_layers.get_mut(pt).unwrap().0 = has_bg;
+            self.ch_layers.get_mut(pt).unwrap().0 = has_fg;
+        } else {
+            self.bg_layers.get_mut(pt).unwrap().0 = false;
+            self.ch_layers.get_mut(pt).unwrap().0 = false;
         }
     }
 }
@@ -236,7 +232,7 @@ async fn main() {
         || {
             Arc::new(RwLock::new(PosIntEditor::new(16)))
         },
-        nested::list::ListEditorStyle::Clist
+        nested::list::ListEditorStyle::Path
     );
 
     color_editor.goto(nested::tree_nav::TreeCursor {
@@ -258,7 +254,7 @@ async fn main() {
         color_collector.clone()
     );
 
-    compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(2, 2)));
+    compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(0, 0)));
 
     let color_view = color_port.outer().get_view();
 
@@ -328,6 +324,19 @@ async fn main() {
         term_writer.show().await.expect("output error!");
     });
 
+
+    
+    let color_layer_id = renderer.lock().unwrap().new_layer_2d();
+    renderer.lock().unwrap().update_camera_2d(color_layer_id, Camera2d{
+        extent: Vec2::new(4.0, 4.0),
+        location: Vec2::new(-2.0, -2.0),
+        rotation: 0.0
+    });
+    renderer.lock().unwrap().set_layer_info(color_layer_id.into(), LayerInfo{
+        extent: (600, 600),
+        location: (200,100)
+    });
+    
     event_loop.run(move |event, _target, control_flow|{
         //Set to polling for now, might be overwritten
         //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderer.lock().unwrap()s don't work that hard
@@ -344,11 +353,43 @@ async fn main() {
             }
             winit::event::Event::RedrawRequested(_) => {
                 for pt in nested::grid::GridWindowIterator::from(
-                    Point2::new(0, 0) .. Point2::new(10, 4)
+                    Point2::new(0, 0) .. Point2::new(30, 1)
                 ) {
                     sdf_term.write().unwrap().update(&pt);
                 }
-                sdf_term.write().unwrap().update_order();
+
+                let c = color_view.get();
+                let color_stream = PrimaryStream2d::new()
+                    .push(
+                        SecondaryStream2d::new(
+                            Union,
+                            Box2d {
+                                extent: Vec2::new(0.5, 0.5)
+                            }
+                        ).push_mod(
+                            Color(
+                                Vec3::new(
+                                    (c.0 as f32 / 255.0).clamp(0.0, 1.0),
+                                    (c.1 as f32 / 255.0).clamp(0.0, 1.0),
+                                    (c.2 as f32 / 255.0).clamp(0.0, 1.0),
+                                )
+                            )
+                        ).push_mod(
+                            Round{radius: 0.2}
+                        ).build()
+                    ).build();
+
+                renderer.lock().unwrap().update_sdf_2d(color_layer_id, color_stream);
+                renderer.lock().unwrap().set_layer_order(
+                    vec![
+                        sdf_term.write().unwrap().get_order().into_iter(),
+                        vec![ color_layer_id.into() ].into_iter()
+                    ]
+                        .into_iter()
+                        .flatten()
+                        .collect::<Vec<_>>()
+                        .as_slice()
+                );
 
                 renderer.lock().unwrap().render(&window);
             }

From 880610c39dce0f1e4e652c749456d6b3fc607dbd Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 02:06:24 +0200
Subject: [PATCH 07/16] IntegerEditor: reverse digit sequence in get_value() to
 use the more commonplace endiannes as default

---
 nested/src/integer/editor.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/nested/src/integer/editor.rs b/nested/src/integer/editor.rs
index 72d2678..aee6c37 100644
--- a/nested/src/integer/editor.rs
+++ b/nested/src/integer/editor.rs
@@ -106,7 +106,7 @@ impl PosIntEditor {
     pub fn get_value(&self) -> u32 {
         let mut value = 0;
         let mut weight = 1;
-        for digit_value in self.get_data_port().get_view().unwrap().iter() {
+        for digit_value in self.get_data_port().get_view().unwrap().iter().collect::<Vec<_>>().into_iter().rev() {
             value += digit_value * weight;
             weight *= self.radix;
         }

From d9b52d5fecbed9bcf80545102010ed1994939bf6 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 02:18:26 +0200
Subject: [PATCH 08/16] fix cargo dependencies

---
 sdf_editor/Cargo.toml | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sdf_editor/Cargo.toml b/sdf_editor/Cargo.toml
index 44b1df3..6394ec7 100644
--- a/sdf_editor/Cargo.toml
+++ b/sdf_editor/Cargo.toml
@@ -6,12 +6,13 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-nako = {git= "https://gitlab.com/tendsinmende/nako.git"}
-nako_std = {git= "https://gitlab.com/tendsinmende/nako.git"}
-nakorender = {git="https://gitlab.com/tendsinmende/nako.git", default-features = false}
+nako = {git= "https://gitlab.com/senvas/nako.git"}
+nako_std = {git= "https://gitlab.com/senvas/nako.git"}
+nakorender = {git="https://gitlab.com/senvas/nako.git", default-features = false}
 nested = { path = "../nested" }
 cgmath = "*"
 termion = "*"
+font-kit = "*"
 
 [dependencies.async-std]
 version = "1.9.0"

From 9633986f6c3b48af8defe49cf702363ec55a7a08 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 10:51:47 +0200
Subject: [PATCH 09/16] cleanup SdfTerm

---
 sdf_editor/Cargo.toml  |   6 +-
 sdf_editor/src/main.rs | 152 ++++++++++++++++++++---------------------
 2 files changed, 76 insertions(+), 82 deletions(-)

diff --git a/sdf_editor/Cargo.toml b/sdf_editor/Cargo.toml
index 6394ec7..d0224df 100644
--- a/sdf_editor/Cargo.toml
+++ b/sdf_editor/Cargo.toml
@@ -6,9 +6,9 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-nako = {git= "https://gitlab.com/senvas/nako.git"}
-nako_std = {git= "https://gitlab.com/senvas/nako.git"}
-nakorender = {git="https://gitlab.com/senvas/nako.git", default-features = false}
+nako = {git= "https://git.exobiont.de/senvas/nako.git"}
+nako_std = {git= "https://git.exobiont.de/senvas/nako.git"}
+nakorender = {git="https://git.exobiont.de/senvas/nako.git", default-features = false}
 nested = { path = "../nested" }
 cgmath = "*"
 termion = "*"
diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 7881208..65b80a9 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -1,3 +1,4 @@
+
 use{
     std::{
         sync::{Arc, RwLock, Mutex},
@@ -70,81 +71,33 @@ impl Observer<dyn SequenceView<Item = u32>> for ColorCollector {
     }
 }
 
-
-struct TermAtomSDF {
-    atom: TerminalAtom
-}
-
-impl TermAtomSDF {
-    fn new(atom: TerminalAtom) -> Self {
-        TermAtomSDF {
-            atom
-        }
-    }
-
-    fn update_bg(&self, layer_id: LayerId2d, renderer: &mut MarpBackend) {
-        let mut stream = PrimaryStream2d::new();
-
-        let (r,g,b) = self.atom.style.bg_color.unwrap_or((0,0,0));
-
-            stream = stream.push(
-                SecondaryStream2d::new(
-                    Union,
-                    Box2d {
-                        extent: Vec2::new(0.6, 1.0)
-                    }
-                ).push_mod(
-                    Color(
-                        Vec3::new(
-                            (r as f32 / 255.0).clamp(0.0, 1.0),
-                            (g as f32 / 255.0).clamp(0.0, 1.0),
-                            (b as f32 / 255.0).clamp(0.0, 1.0),
-                        )
-                    )
-                ).build()
-            );
-
-        renderer.update_sdf_2d(layer_id, stream.build());
-    }
-
-    fn update_ch(&self, layer_id: LayerId2d, renderer: &mut MarpBackend) {
-        let mut stream = PrimaryStream2d::new();
-        
-        if let Some(c) = self.atom.c {
-            let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap();
-            let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.01);
-
-            let (r,g,b) = self.atom.style.fg_color.unwrap_or((0, 0, 0));
-
-            ch.color = Vec3::new(
-                (r as f32 / 255.0).clamp(0.0, 1.0),
-                (g as f32 / 255.0).clamp(0.0, 1.0),
-                (b as f32 / 255.0).clamp(0.0, 1.0),
-            );
-
-            stream = ch.record_character(stream);
-        }
-
-        renderer.update_sdf_2d(layer_id, stream.build());
-    }
-}
-
 struct SdfTerm {
-    src_view: Arc<dyn TerminalView>,
+    pub src_view: Option<Arc<dyn TerminalView>>,
     bg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
-    ch_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
+    fg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
+    font: Font,
     renderer: Arc<Mutex<MarpBackend>>
 }
 
 impl SdfTerm {
-    fn get_order(&mut self) -> Vec<LayerId> {
+    pub fn new(renderer: Arc<Mutex<MarpBackend>>) -> Self {
+        SdfTerm {
+            src_view: None,
+            bg_layers: HashMap::new(),
+            fg_layers: HashMap::new(),
+            font: Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap(),
+            renderer
+        }
+    }
+
+    pub fn get_order(&mut self) -> Vec<LayerId> {
         vec![
             self.bg_layers.iter().filter(
                 |(_pt, (active, _id))| *active
             )
                 .collect::<Vec<_>>()
                 .into_iter(),
-            self.ch_layers.iter().filter(
+            self.fg_layers.iter().filter(
                 |(_pt, (active, _id))| *active
             )
                 .collect::<Vec<_>>()
@@ -156,7 +109,7 @@ impl SdfTerm {
             .collect::<Vec<_>>()
     }
 
-    fn update(&mut self, pt: &Point2<i16>) {
+    pub fn update(&mut self, pt: &Point2<i16>) {
         if self.bg_layers.get(pt).is_none() {
             let id = self.renderer.lock().unwrap().new_layer_2d();
 
@@ -176,7 +129,7 @@ impl SdfTerm {
 
             self.bg_layers.insert(*pt, (false, id));
         }
-        if self.ch_layers.get(pt).is_none() {
+        if self.fg_layers.get(pt).is_none() {
             let id = self.renderer.lock().unwrap().new_layer_2d();
 
             self.renderer.lock().unwrap().update_camera_2d(
@@ -193,22 +146,68 @@ impl SdfTerm {
                     location: (pt.x as usize * 60, pt.y as usize * 100)
                 });
 
-            self.ch_layers.insert(*pt, (false, id));
+            self.fg_layers.insert(*pt, (false, id));
         }
 
         if let Some(atom) = self.src_view.get(pt) {
-            let atom_stream_builder = TermAtomSDF::new(atom);
-            atom_stream_builder.update_bg(self.bg_layers.get(pt).unwrap().1, &mut *self.renderer.lock().unwrap());
-            atom_stream_builder.update_ch(self.ch_layers.get(pt).unwrap().1, &mut *self.renderer.lock().unwrap());
 
+            // background layer
+            if let Some((r,g,b)) = atom.style.bg_color {
+                let mut stream = PrimaryStream2d::new()
+                    .push(
+                        SecondaryStream2d::new(
+                            Union,
+                            Box2d {
+                                extent: Vec2::new(0.6, 1.0)
+                            }
+                        ).push_mod(
+                            Color(
+                                Vec3::new(
+                                    (r as f32 / 255.0).clamp(0.0, 1.0),
+                                    (g as f32 / 255.0).clamp(0.0, 1.0),
+                                    (b as f32 / 255.0).clamp(0.0, 1.0),
+                                )
+                            )
+                        ).build()
+                    );
+
+                self.renderer.lock().unwrap().update_sdf_2d(self.bg_layers.get(pt).unwrap().1, stream.build());
+                self.bg_layers.get_mut(pt).unwrap().0 = true;
+            } else {
+                self.bg_layers.get_mut(pt).unwrap().0 = false;                
+            }
+
+            // foreground layer
+            if let Some(c) = atom.c {
+                let mut ch = Character::from_font(&self.font, c).with_size(1.0).with_tesselation_factor(0.01);
+
+                let (r,g,b) = atom.style.fg_color.unwrap_or((0, 0, 0));
+
+                ch.color = Vec3::new(
+                    (r as f32 / 255.0).clamp(0.0, 1.0),
+                    (g as f32 / 255.0).clamp(0.0, 1.0),
+                    (b as f32 / 255.0).clamp(0.0, 1.0),
+                );
+
+                let mut stream = PrimaryStream2d::new();
+                stream = ch.record_character(stream);
+
+                self.renderer.lock().unwrap().update_sdf_2d(self.fg_layers.get(pt).unwrap().1, stream.build());
+                self.fg_layers.get_mut(pt).unwrap().0 = true;
+            } else {
+                self.fg_layers.get_mut(pt).unwrap().0 = false;                
+            }
+            
+            
+            
             let has_bg = atom.style.bg_color.is_some();
             let has_fg = atom.c.unwrap_or(' ') != ' ';
 
             self.bg_layers.get_mut(pt).unwrap().0 = has_bg;
-            self.ch_layers.get_mut(pt).unwrap().0 = has_fg;
+            self.fg_layers.get_mut(pt).unwrap().0 = has_fg;
         } else {
             self.bg_layers.get_mut(pt).unwrap().0 = false;
-            self.ch_layers.get_mut(pt).unwrap().0 = false;
+            self.fg_layers.get_mut(pt).unwrap().0 = false;
         }
     }
 }
@@ -265,12 +264,8 @@ async fn main() {
     let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
     let mut renderer = Arc::new(Mutex::new(nakorender::marp::MarpBackend::new(&window, &event_loop)));
 
-    let mut sdf_term = Arc::new(RwLock::new(SdfTerm {
-        src_view: term_port.outer().get_view().unwrap(),
-        bg_layers: HashMap::new(),
-        ch_layers: HashMap::new(),
-        renderer: renderer.clone()
-    }));
+    let mut sdf_term = Arc::new(RwLock::new(SdfTerm::new(renderer.clone())));
+    sdf_term.write().unwrap().src_view = term_port.outer().get_view();
     //term_port.outer().add_observer(sdf_term.clone());
 
     async_std::task::spawn(
@@ -324,7 +319,6 @@ async fn main() {
         term_writer.show().await.expect("output error!");
     });
 
-
     
     let color_layer_id = renderer.lock().unwrap().new_layer_2d();
     renderer.lock().unwrap().update_camera_2d(color_layer_id, Camera2d{
@@ -336,7 +330,7 @@ async fn main() {
         extent: (600, 600),
         location: (200,100)
     });
-    
+
     event_loop.run(move |event, _target, control_flow|{
         //Set to polling for now, might be overwritten
         //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderer.lock().unwrap()s don't work that hard

From b708545b9696480e26f63544acbb8d4efc24d1b6 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 11:02:35 +0200
Subject: [PATCH 10/16] SdfTerm: remove outdated lines

---
 sdf_editor/src/main.rs | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 65b80a9..e773d58 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -197,14 +197,7 @@ impl SdfTerm {
             } else {
                 self.fg_layers.get_mut(pt).unwrap().0 = false;                
             }
-            
-            
-            
-            let has_bg = atom.style.bg_color.is_some();
-            let has_fg = atom.c.unwrap_or(' ') != ' ';
 
-            self.bg_layers.get_mut(pt).unwrap().0 = has_bg;
-            self.fg_layers.get_mut(pt).unwrap().0 = has_fg;
         } else {
             self.bg_layers.get_mut(pt).unwrap().0 = false;
             self.fg_layers.get_mut(pt).unwrap().0 = false;

From 83386d5bd9a8a4998ddd24a95dd9ac96f70bba69 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 11:10:05 +0200
Subject: [PATCH 11/16] SdfTerm: simplify get_order()

---
 sdf_editor/src/main.rs | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index e773d58..de5e7f5 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -92,20 +92,18 @@ impl SdfTerm {
 
     pub fn get_order(&mut self) -> Vec<LayerId> {
         vec![
-            self.bg_layers.iter().filter(
-                |(_pt, (active, _id))| *active
-            )
-                .collect::<Vec<_>>()
-                .into_iter(),
-            self.fg_layers.iter().filter(
-                |(_pt, (active, _id))| *active
-            )
-                .collect::<Vec<_>>()
-                .into_iter()
+            self.bg_layers.iter(),
+            self.fg_layers.iter()
         ]
             .into_iter()
             .flatten()
-            .map(|(_,(_,id))| (*id).into())
+            .filter_map(
+                |(_pt,(active,id))|
+                if *active {
+                    Some((*id).into())
+                } else {
+                    None
+                })
             .collect::<Vec<_>>()
     }
 
@@ -274,8 +272,6 @@ async fn main() {
                                 Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
                             )
                         );
-
-                        
                     }
                     TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |

From 6247dcc9f50603ad5339b92ee5f2e3f5347ea172 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 12:53:08 +0200
Subject: [PATCH 12/16] SdfTerm: impl Observer to only update modified layers

---
 sdf_editor/src/main.rs | 62 ++++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index de5e7f5..c404ec9 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -75,7 +75,7 @@ struct SdfTerm {
     pub src_view: Option<Arc<dyn TerminalView>>,
     bg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
     fg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
-    font: Font,
+    //font: Arc<RwLock<Font>>,
     renderer: Arc<Mutex<MarpBackend>>
 }
 
@@ -85,12 +85,12 @@ impl SdfTerm {
             src_view: None,
             bg_layers: HashMap::new(),
             fg_layers: HashMap::new(),
-            font: Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap(),
+            //font: Arc::new(RwLock::new(Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap())),
             renderer
         }
     }
 
-    pub fn get_order(&mut self) -> Vec<LayerId> {
+    pub fn get_order(&self) -> Vec<LayerId> {
         vec![
             self.bg_layers.iter(),
             self.fg_layers.iter()
@@ -177,7 +177,8 @@ impl SdfTerm {
 
             // foreground layer
             if let Some(c) = atom.c {
-                let mut ch = Character::from_font(&self.font, c).with_size(1.0).with_tesselation_factor(0.01);
+                let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap();
+                let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.01);
 
                 let (r,g,b) = atom.style.fg_color.unwrap_or((0, 0, 0));
 
@@ -202,14 +203,21 @@ impl SdfTerm {
         }
     }
 }
-/*
+
 impl Observer<dyn TerminalView> for SdfTerm {
+    fn reset(&mut self, new_view: Option<Arc<dyn TerminalView>>) {
+        self.src_view = new_view;
+
+        for pt in self.src_view.area().unwrap_or(vec![]) {
+            self.notify(&pt);
+        }
+    }
+
     fn notify(&mut self, pt: &Point2<i16>) {
         self.update(pt);
-        self.update_order();
     }
 }
-*/
+
 #[async_std::main]
 async fn main() {
     let term_port = ViewPort::new();
@@ -246,33 +254,21 @@ async fn main() {
 
     compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(0, 0)));
 
-    let color_view = color_port.outer().get_view();
-
-    let cp = color_port.clone();
     let tp = term_port.clone();
-
-    let event_loop = nakorender::winit::event_loop::EventLoop::new();
-    let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
-    let mut renderer = Arc::new(Mutex::new(nakorender::marp::MarpBackend::new(&window, &event_loop)));
-
-    let mut sdf_term = Arc::new(RwLock::new(SdfTerm::new(renderer.clone())));
-    sdf_term.write().unwrap().src_view = term_port.outer().get_view();
-    //term_port.outer().add_observer(sdf_term.clone());
-
     async_std::task::spawn(
         async move {
             loop {
-                cp.update();
-                tp.update();
-                
                 match term.next_event().await {
-                    TerminalEvent::Resize(new_size) => {
+                    TerminalEvent::Resize(mut new_size) => {
+                        new_size.x = 10;
+                        new_size.y = 5;
                         tp.inner().get_broadcast().notify_each(
                             nested::grid::GridWindowIterator::from(
                                 Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
                             )
                         );
                     }
+
                     TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
                     TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
@@ -308,7 +304,16 @@ async fn main() {
         term_writer.show().await.expect("output error!");
     });
 
-    
+    let event_loop = nakorender::winit::event_loop::EventLoop::new();
+    let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
+    let mut renderer = Arc::new(Mutex::new(nakorender::marp::MarpBackend::new(&window, &event_loop)));
+
+    // terminal view
+    let mut sdf_term = Arc::new(RwLock::new(SdfTerm::new(renderer.clone())));
+    term_port.outer().add_observer(sdf_term.clone());
+
+    // color preview
+    let color_view = color_port.outer().get_view();
     let color_layer_id = renderer.lock().unwrap().new_layer_2d();
     renderer.lock().unwrap().update_camera_2d(color_layer_id, Camera2d{
         extent: Vec2::new(4.0, 4.0),
@@ -335,11 +340,8 @@ async fn main() {
                 window.request_redraw();
             }
             winit::event::Event::RedrawRequested(_) => {
-                for pt in nested::grid::GridWindowIterator::from(
-                    Point2::new(0, 0) .. Point2::new(30, 1)
-                ) {
-                    sdf_term.write().unwrap().update(&pt);
-                }
+                color_port.update();
+                term_port.update();
 
                 let c = color_view.get();
                 let color_stream = PrimaryStream2d::new()
@@ -365,7 +367,7 @@ async fn main() {
                 renderer.lock().unwrap().update_sdf_2d(color_layer_id, color_stream);
                 renderer.lock().unwrap().set_layer_order(
                     vec![
-                        sdf_term.write().unwrap().get_order().into_iter(),
+                        sdf_term.read().unwrap().get_order().into_iter(),
                         vec![ color_layer_id.into() ].into_iter()
                     ]
                         .into_iter()

From f393704054e334b1b2f34750d14dcb9fff4f0c9f Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 10 Sep 2021 13:26:02 +0200
Subject: [PATCH 13/16] sdf color picker: quick n dirty event handling via
 winit

---
 sdf_editor/src/main.rs | 164 ++++++++++++++++++++++++++---------------
 1 file changed, 106 insertions(+), 58 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index c404ec9..624c219 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -177,7 +177,7 @@ impl SdfTerm {
 
             // foreground layer
             if let Some(c) = atom.c {
-                let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap();
+                let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Light.ttf"),0).unwrap();
                 let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.01);
 
                 let (r,g,b) = atom.style.fg_color.unwrap_or((0, 0, 0));
@@ -223,14 +223,11 @@ async fn main() {
     let term_port = ViewPort::new();
     let compositor = TerminalCompositor::new(term_port.inner());
 
-    let mut term = Terminal::new(term_port.outer());
-    let term_writer = term.get_writer();
-
     let mut color_editor = ListEditor::new(
         || {
             Arc::new(RwLock::new(PosIntEditor::new(16)))
         },
-        nested::list::ListEditorStyle::Path
+        nested::list::ListEditorStyle::HorizontalSexpr
     );
 
     color_editor.goto(nested::tree_nav::TreeCursor {
@@ -254,56 +251,6 @@ async fn main() {
 
     compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(0, 0)));
 
-    let tp = term_port.clone();
-    async_std::task::spawn(
-        async move {
-            loop {
-                match term.next_event().await {
-                    TerminalEvent::Resize(mut new_size) => {
-                        new_size.x = 10;
-                        new_size.y = 5;
-                        tp.inner().get_broadcast().notify_each(
-                            nested::grid::GridWindowIterator::from(
-                                Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
-                            )
-                        );
-                    }
-
-                    TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
-                    TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
-                    TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
-
-                    TerminalEvent::Input(Event::Key(Key::Left)) => {
-                        color_editor.pxev();
-                    }
-                    TerminalEvent::Input(Event::Key(Key::Right)) => {
-                        color_editor.nexd();
-                    }
-                    TerminalEvent::Input(Event::Key(Key::Up)) => {
-                        color_editor.up();
-                    }
-                    TerminalEvent::Input(Event::Key(Key::Down)) => {
-                        color_editor.dn();
-                        color_editor.goto_home();
-                    }
-                    TerminalEvent::Input(Event::Key(Key::Home)) => {
-                        color_editor.goto_home();
-                    }
-                    TerminalEvent::Input(Event::Key(Key::End)) => {
-                        color_editor.goto_end();
-                    }
-                    event => {
-                        color_editor.handle_terminal_event(&event);
-                    }
-                }
-            }
-        }
-    );
-
-    async_std::task::spawn(async move {
-        term_writer.show().await.expect("output error!");
-    });
-
     let event_loop = nakorender::winit::event_loop::EventLoop::new();
     let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
     let mut renderer = Arc::new(Mutex::new(nakorender::marp::MarpBackend::new(&window, &event_loop)));
@@ -330,11 +277,112 @@ async fn main() {
         //TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderer.lock().unwrap()s don't work that hard
         //if nothing changes. So should be okay for a alpha style programm.
         *control_flow = winit::event_loop::ControlFlow::Poll;
-        
+
         //now check if a rerender was requested, or if we worked on all
         //events on that batch
         match event{
             winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::Resized(newsize)} => {
+                
+            }
+            winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::KeyboardInput{ device_id, input, is_synthetic }} => {
+                if input.state == winit::event::ElementState::Pressed {
+                    if let Some(kc) = input.virtual_keycode {
+                        match kc {
+                            winit::event::VirtualKeyCode::Space |
+                            winit::event::VirtualKeyCode::Return => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char(' '))));
+                            }
+                            winit::event::VirtualKeyCode::Key0 |
+                            winit::event::VirtualKeyCode::Numpad0 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('0'))));
+                            }
+                            winit::event::VirtualKeyCode::Key1 |
+                            winit::event::VirtualKeyCode::Numpad1 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('1'))));
+                            }
+                            winit::event::VirtualKeyCode::Key2 |
+                            winit::event::VirtualKeyCode::Numpad2 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('2'))));
+                            }
+                            winit::event::VirtualKeyCode::Key3 |
+                            winit::event::VirtualKeyCode::Numpad3 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('3'))));
+                            }
+                            winit::event::VirtualKeyCode::Key4 |
+                            winit::event::VirtualKeyCode::Numpad4 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('4'))));
+                            }
+                            winit::event::VirtualKeyCode::Key5 |
+                            winit::event::VirtualKeyCode::Numpad5 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('5'))));
+                            }
+                            winit::event::VirtualKeyCode::Key6 |
+                            winit::event::VirtualKeyCode::Numpad6 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('6'))));
+                            }
+                            winit::event::VirtualKeyCode::Key7 |
+                            winit::event::VirtualKeyCode::Numpad7 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('7'))));
+                            }
+                            winit::event::VirtualKeyCode::Key8 |
+                            winit::event::VirtualKeyCode::Numpad8 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('8'))));
+                            }
+                            winit::event::VirtualKeyCode::Key9 |
+                            winit::event::VirtualKeyCode::Numpad9 => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('9'))));
+                            }
+                            winit::event::VirtualKeyCode::A => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('a'))));
+                            }
+                            winit::event::VirtualKeyCode::B => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('b'))));
+                            }
+                            winit::event::VirtualKeyCode::C => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('c'))));
+                            }
+                            winit::event::VirtualKeyCode::D => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('d'))));
+                            }
+                            winit::event::VirtualKeyCode::E => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('e'))));
+                            }
+                            winit::event::VirtualKeyCode::F => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('f'))));
+                            }
+                            winit::event::VirtualKeyCode::Tab => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Insert)));
+                            }
+                            winit::event::VirtualKeyCode::Delete => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Delete)));
+                            }
+                            winit::event::VirtualKeyCode::Back => {
+                                color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Backspace)));
+                            }
+                            winit::event::VirtualKeyCode::Left => {
+                                color_editor.pxev();
+                            }
+                            winit::event::VirtualKeyCode::Right => {
+                                color_editor.nexd();
+                            }
+                            winit::event::VirtualKeyCode::Up => {
+                                color_editor.up();
+                            }
+                            winit::event::VirtualKeyCode::Down => {
+                                color_editor.dn();
+                                color_editor.goto_home();
+                            }
+                            winit::event::VirtualKeyCode::Home => {
+                                color_editor.goto_home();
+                            }
+                            winit::event::VirtualKeyCode::End => {
+                                color_editor.goto_end();
+                            }
+                            _ => {
+                            }
+                        }
+                    }
+                }
             }
             winit::event::Event::MainEventsCleared => {
                 window.request_redraw();
@@ -367,8 +415,8 @@ async fn main() {
                 renderer.lock().unwrap().update_sdf_2d(color_layer_id, color_stream);
                 renderer.lock().unwrap().set_layer_order(
                     vec![
-                        sdf_term.read().unwrap().get_order().into_iter(),
-                        vec![ color_layer_id.into() ].into_iter()
+                        vec![ color_layer_id.into() ].into_iter(),
+                        sdf_term.read().unwrap().get_order().into_iter()
                     ]
                         .into_iter()
                         .flatten()

From cdeb0f9bc8ddc20c723ea3b7e891f333977adcf5 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sun, 12 Sep 2021 17:39:24 +0200
Subject: [PATCH 14/16] list editor: fix out of bounds on backspace

---
 nested/src/list/editor.rs | 40 +++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/nested/src/list/editor.rs b/nested/src/list/editor.rs
index f29638b..736d27d 100644
--- a/nested/src/list/editor.rs
+++ b/nested/src/list/editor.rs
@@ -147,7 +147,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
             );
             return TreeNavResult::Continue;
         }
-        
+
         if i < self.data.len() {
             match cur.mode {
                 ListCursorMode::Insert => {
@@ -327,6 +327,8 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                             }
                         );
                     }
+                } else {
+                    self.goto_home();
                 }
                 TreeNavResult::Continue
             }
@@ -424,7 +426,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                         TreeNavResult::Exit => {
                             drop(cur_edit);
                             drop(ce);
-                                self.up();
+                            self.up();
 
                             if i+1 < self.data.len() {
 
@@ -477,10 +479,10 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                 ListCursorMode::Insert => {
                     match event {
                         TerminalEvent::Input(Event::Key(Key::Backspace)) => {
-                            if idx > 0 {
-                                self.data.remove(idx-1);
+                            if idx > 0 && idx <= self.data.len() {
                                 cur.idx = Some(idx-1);
                                 self.cursor.set(cur);
+                                self.data.remove(idx-1);
                                 TerminalEditorResult::Continue
                             } else {
                                 TerminalEditorResult::Exit
@@ -551,24 +553,26 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                         TerminalEditorResult::Exit => {
                             cur_edit.up();
                             drop(cur_edit);
+                            drop(ce);
 
                             match event {
-                                TerminalEvent::Input(Event::Key(Key::Char(' '))) => {
-                                    // split..
-                                    self.cursor.set(ListCursor {
-                                        mode: ListCursorMode::Insert,
-                                        idx: Some(idx+1)
-                                    });
-                                }
                                 TerminalEvent::Input(Event::Key(Key::Backspace)) => {
+                                    // todo: join instead of remove
                                     self.cursor.set(ListCursor {
                                         mode: ListCursorMode::Insert,
                                         idx: Some(idx)
                                     });
 
-                                    self.data.remove(idx); // todo: join instead of remove
+                                    self.data.remove(idx);
+                                }
+                                _ => {
+                                    // todo: split
+
+                                    self.cursor.set(ListCursor {
+                                        mode: ListCursorMode::Insert,
+                                        idx: Some(idx+1)
+                                    });
                                 }
-                                _ => {}
                             }
                         },
                         TerminalEditorResult::Continue => {}
@@ -611,11 +615,11 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
                             atom.add_style_front(TerminalStyle::bg_color((90,60,200)))
                         ),
                     ListEditorViewSegment::Modify(sub_view) => {
-                        sub_view.clone()/*.map_item(
+                        sub_view.clone().map_item(
                             |_pt, atom|
-                            atom//.add_style_back(TerminalStyle::bg_color((0,0,0)))
+                            atom.add_style_back(TerminalStyle::bg_color((22,15,50)))
                                 //.add_style_back(TerminalStyle::bold(true))
-                        )*/
+                        )
                     },
                     ListEditorViewSegment::View(sub_view) =>
                         sub_view.clone()
@@ -624,7 +628,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
     }
 
     pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
-        self.get_seg_seq_view().horizontal_sexpr_view(0)
+        self.get_seg_seq_view().horizontal_sexpr_view(1)
     }
 
     pub fn vertical_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
@@ -664,7 +668,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
             .to_grid_horizontal()
             .flatten()
     }
-    
+
     pub fn new(make_item_editor: FnMakeItemEditor, style: ListEditorStyle) -> Self {
         let cursor_port = ViewPort::new();
         let data_port = ViewPort::new();

From 029d2c4e029bd8eb796cbb007a8529d819bf173f Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sun, 12 Sep 2021 17:40:03 +0200
Subject: [PATCH 15/16] SdfTerm: calculate layer size & offset with
 configurable font size

---
 sdf_editor/src/main.rs | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 624c219..3181b41 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -72,10 +72,13 @@ impl Observer<dyn SequenceView<Item = u32>> for ColorCollector {
 }
 
 struct SdfTerm {
-    pub src_view: Option<Arc<dyn TerminalView>>,
+    src_view: Option<Arc<dyn TerminalView>>,
     bg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
     fg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
-    //font: Arc<RwLock<Font>>,
+
+    font_height: usize,
+    //font: Mutex<Font>,
+
     renderer: Arc<Mutex<MarpBackend>>
 }
 
@@ -85,7 +88,8 @@ impl SdfTerm {
             src_view: None,
             bg_layers: HashMap::new(),
             fg_layers: HashMap::new(),
-            //font: Arc::new(RwLock::new(Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap())),
+            font_height: 60,
+            //font: Mutex::new(Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap()),
             renderer
         }
     }
@@ -121,8 +125,8 @@ impl SdfTerm {
             self.renderer.lock().unwrap().set_layer_info(
                 id.into(),
                 LayerInfo {
-                    extent: (60, 100),
-                    location: (pt.x as usize * 60, pt.y as usize * 100)
+                    extent: (1 + self.font_height / 2, self.font_height),
+                    location: (pt.x as usize * self.font_height / 2, pt.y as usize * self.font_height)
                 });
 
             self.bg_layers.insert(*pt, (false, id));
@@ -140,8 +144,8 @@ impl SdfTerm {
             self.renderer.lock().unwrap().set_layer_info(
                 id.into(),
                 LayerInfo {
-                    extent: (60, 100),
-                    location: (pt.x as usize * 60, pt.y as usize * 100)
+                    extent: (1 + self.font_height / 2, self.font_height),
+                    location: (pt.x as usize * self.font_height / 2, pt.y as usize * self.font_height)
                 });
 
             self.fg_layers.insert(*pt, (false, id));

From b081c4311fb2a8765f0ac7c23f11f9bf96d5eb22 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sun, 12 Sep 2021 22:57:58 +0200
Subject: [PATCH 16/16] use UVec2 in Layer info

---
 sdf_editor/src/main.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sdf_editor/src/main.rs b/sdf_editor/src/main.rs
index 3181b41..4cd1609 100644
--- a/sdf_editor/src/main.rs
+++ b/sdf_editor/src/main.rs
@@ -24,7 +24,7 @@ use{
     },
     nako::{
         stream::{SecondaryStream2d, PrimaryStream2d},
-        glam::{Vec2, Vec3},
+        glam::{Vec2, Vec3, UVec2},
         operations::{
             planar::primitives2d::Box2d,
             volumetric::{Color, Union, Round},
@@ -76,7 +76,7 @@ struct SdfTerm {
     bg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
     fg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
 
-    font_height: usize,
+    font_height: u32,
     //font: Mutex<Font>,
 
     renderer: Arc<Mutex<MarpBackend>>
@@ -125,8 +125,8 @@ impl SdfTerm {
             self.renderer.lock().unwrap().set_layer_info(
                 id.into(),
                 LayerInfo {
-                    extent: (1 + self.font_height / 2, self.font_height),
-                    location: (pt.x as usize * self.font_height / 2, pt.y as usize * self.font_height)
+                    extent: UVec2::new(1 + self.font_height / 2, self.font_height),
+                    location: UVec2::new(pt.x as u32 * self.font_height / 2, pt.y as u32 * self.font_height)
                 });
 
             self.bg_layers.insert(*pt, (false, id));
@@ -144,8 +144,8 @@ impl SdfTerm {
             self.renderer.lock().unwrap().set_layer_info(
                 id.into(),
                 LayerInfo {
-                    extent: (1 + self.font_height / 2, self.font_height),
-                    location: (pt.x as usize * self.font_height / 2, pt.y as usize * self.font_height)
+                    extent: UVec2::new(1 + self.font_height / 2, self.font_height),
+                    location: UVec2::new(pt.x as u32 * self.font_height / 2, pt.y as u32 * self.font_height)
                 });
 
             self.fg_layers.insert(*pt, (false, id));
@@ -272,8 +272,8 @@ async fn main() {
         rotation: 0.0
     });
     renderer.lock().unwrap().set_layer_info(color_layer_id.into(), LayerInfo{
-        extent: (600, 600),
-        location: (200,100)
+        extent: UVec2::new(600, 600),
+        location: UVec2::new(200,100)
     });
 
     event_loop.run(move |event, _target, control_flow|{