use{ std::{ sync::{Arc, RwLock, Mutex}, collections::HashMap }, cgmath::{Point2, Vector2}, termion::event::{Event, Key}, nested::{ core::{ View, ViewPort, Observer, ObserverExt, OuterViewPort, port::UpdateTask }, singleton::{SingletonBuffer, SingletonView}, sequence::{SequenceView}, integer::{PosIntEditor}, terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalView, TerminalCompositor, TerminalEvent, TerminalEditor}, list::{ListEditor}, tree_nav::{TreeNav} }, nako::{ stream::{SecondaryStream2d, PrimaryStream2d}, glam::{Vec2, Vec3, UVec2, IVec2}, operations::{ planar::primitives2d::Box2d, volumetric::{Color, Union, Round}, }, }, 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>>, 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> for ColorCollector { fn reset(&mut self, new_view: Option>>) { self.src_view = new_view; self.update(); } fn notify(&mut self, idx: &usize) { self.update(); } } struct SdfTerm { src_view: Option>, bg_layers: HashMap, (bool, LayerId2d)>, fg_layers: HashMap, (bool, LayerId2d)>, font_height: u32, //font: Mutex, renderer: Arc> } impl SdfTerm { pub fn new(renderer: Arc>) -> Self { SdfTerm { src_view: None, bg_layers: HashMap::new(), fg_layers: HashMap::new(), font_height: 60, //font: Mutex::new(Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap()), renderer } } pub fn get_order(&self) -> Vec { vec![ self.bg_layers.iter(), self.fg_layers.iter() ] .into_iter() .flatten() .filter_map( |(_pt,(active,id))| if *active { Some((*id).into()) } else { None }) .collect::>() } pub fn update(&mut self, pt: &Point2) { 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: UVec2::new(1 + self.font_height / 2, self.font_height), location: IVec2::new(pt.x as i32 * self.font_height as i32 / 2, pt.y as i32 * self.font_height as i32) }); self.bg_layers.insert(*pt, (false, id)); } if self.fg_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: UVec2::new(1 + self.font_height / 2, self.font_height), location: IVec2::new(pt.x as i32 * self.font_height as i32 / 2, pt.y as i32 * self.font_height as i32) }); self.fg_layers.insert(*pt, (false, id)); } if let Some(atom) = self.src_view.get(pt) { // 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 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)); 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; } } else { self.bg_layers.get_mut(pt).unwrap().0 = false; self.fg_layers.get_mut(pt).unwrap().0 = false; } } } impl Observer for SdfTerm { fn reset(&mut self, new_view: Option>) { self.src_view = new_view; for pt in self.src_view.area().unwrap_or(vec![]) { self.notify(&pt); } } fn notify(&mut self, pt: &Point2) { self.update(pt); } } #[async_std::main] async fn main() { let term_port = ViewPort::new(); let compositor = TerminalCompositor::new(term_port.inner()); let mut color_editor = ListEditor::new( || { Arc::new(RwLock::new(PosIntEditor::new(16))) }, nested::list::ListEditorStyle::HorizontalSexpr ); 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((200, 200, 0), color_port.inner()) })); let col_seq_port = color_editor.get_data_port().map( |sub_editor| sub_editor.read().unwrap().get_value() ); 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(0, 0))); 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), location: Vec2::new(-2.0, -2.0), rotation: 0.0 }); renderer.lock().unwrap().set_layer_info(color_layer_id.into(), LayerInfo{ extent: UVec2::new(600, 600), location: IVec2::new(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 //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(); } winit::event::Event::RedrawRequested(_) => { color_port.update(); term_port.update(); 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![ vec![ color_layer_id.into() ].into_iter(), sdf_term.read().unwrap().get_order().into_iter() ] .into_iter() .flatten() .collect::>() .as_slice() ); renderer.lock().unwrap().render(&window); } _ => {}, } }) }