From f3fa8a7af18ee776fc4373b50a32d8f3e99a79bd Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Tue, 12 Jan 2021 23:13:27 +0100 Subject: [PATCH] map_item() projection for index views --- src/index/map_item.rs | 105 ++++++++++++++++++++++++++++++++++++++++++ src/index/mod.rs | 2 + src/main.rs | 46 ++++++++++++++---- 3 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 src/index/map_item.rs diff --git a/src/index/map_item.rs b/src/index/map_item.rs new file mode 100644 index 0000000..c9bdbb0 --- /dev/null +++ b/src/index/map_item.rs @@ -0,0 +1,105 @@ +pub use { + std::{ + sync::{Arc, RwLock}, + ops::Range + }, + crate::{ + core::{ + View, + Observer, + ObserverBroadcast, + ViewPort, + InnerViewPort, + OuterViewPort + }, + index::{IndexView} + } +}; + +impl OuterViewPort> { + pub fn map_item< + DstItem: Default + 'static, + F: Fn(&Item) -> DstItem + Send + Sync + 'static + >( + &self, + f: F + ) -> OuterViewPort> { + let port = ViewPort::new(); + let map = MapIndexItem::new(port.inner(), f); + self.add_observer(map.clone()); + port.into_outer() + } +} + +pub struct MapIndexItem +where SrcView: IndexView + ?Sized, + F: Fn(&SrcView::Item) -> DstItem + Send + Sync +{ + src_view: Option>, + f: F, + cast: Arc>>> +} + +impl MapIndexItem +where Key: 'static, + DstItem: Default + 'static, + SrcView: IndexView + ?Sized + 'static, + F: Fn(&SrcView::Item) -> DstItem + Send + Sync + 'static +{ + fn new( + port: InnerViewPort>, + f: F + ) -> Arc> { + let map = Arc::new(RwLock::new( + MapIndexItem { + src_view: None, + f, + cast: port.get_broadcast() + } + )); + + port.set_view(Some(map.clone())); + map + } +} + +impl View for MapIndexItem +where SrcView: IndexView + ?Sized, + F: Fn(&SrcView::Item) -> DstItem + Send + Sync +{ + type Msg = Key; +} + +impl IndexView for MapIndexItem +where DstItem: Default, + SrcView: IndexView + ?Sized, + F: Fn(&SrcView::Item) -> DstItem + Send + Sync +{ + type Item = DstItem; + + fn get(&self, key: &Key) -> Self::Item { + if let Some(v) = self.src_view.as_ref() { + (self.f)(&v.get(key)) + } else { + DstItem::default() + } + } + + fn range(&self) -> Option> { + self.src_view.as_ref()?.range() + } +} + +impl Observer for MapIndexItem +where SrcView: IndexView + ?Sized, + F: Fn(&SrcView::Item) -> DstItem + Send + Sync +{ + fn reset(&mut self, view: Option>) { + // todo: notify on reset ?? + self.src_view = view; + } + + fn notify(&self, msg: &Key) { + self.cast.notify(msg); + } +} diff --git a/src/index/mod.rs b/src/index/mod.rs index 7aab0c7..bd02c47 100644 --- a/src/index/mod.rs +++ b/src/index/mod.rs @@ -1,4 +1,6 @@ +pub mod map_item; + use { std::{ sync::{Arc, RwLock}, diff --git a/src/main.rs b/src/main.rs index 071ee4f..6e2f903 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,15 +2,14 @@ #![feature(assoc_char_funcs)] pub mod core; -pub mod view; +pub mod index; +pub mod grid; +pub mod sequence; +pub mod singleton; pub mod terminal; pub mod string_editor; -//pub mod singleton_buffer; -//pub mod vec_buffer; -//pub mod sequence_element_projection; - use { async_std::{task}, std::{ @@ -21,7 +20,7 @@ use { termion::event::{Event, Key}, crate::{ core::{View, Observer, ObserverExt, ViewPort}, - view::{*}, + index::{ImplIndexView}, terminal::{ TerminalView, TerminalAtom, @@ -30,6 +29,7 @@ use { Terminal, TerminalCompositor }, + grid::GridOffset } }; @@ -77,7 +77,7 @@ impl ImplIndexView for ScrambleBackground { type Value = Option; fn get(&self, pos: &Point2) -> Option { - if ((pos.x/2) % 2 == 0) ^ ( pos.y % 2 == 0 ) { + if ((pos.x/2) % 2 == 0) ^ (pos.y % 2 == 0) { Some(TerminalAtom::new(char::from((35+(5*pos.y+pos.x)%40) as u8), TerminalStyle::fg_color((40, 40, 40)))) } else { Some(TerminalAtom::new(char::from((35+(pos.y+9*pos.x)%40) as u8), TerminalStyle::fg_color((90, 90, 90)))) @@ -96,7 +96,7 @@ async fn main() { let mut compositor = TerminalCompositor::new(term_port.inner()); compositor.push(ViewPort::::with_view(Arc::new(ScrambleBackground)).into_outer()); - + let mut term = Terminal::new(term_port.outer()); let term_writer = term.get_writer(); @@ -107,11 +107,37 @@ async fn main() { <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> \*/ - compositor.push(ViewPort::::with_view(Arc::new(Checkerboard)).into_outer()); + let offset_port = ViewPort::::new(); + let o = GridOffset::new(offset_port.inner()); + + let checkerboard_port = ViewPort::::with_view(Arc::new(Checkerboard)); + checkerboard_port.add_observer(o.clone()); + + compositor.push(offset_port.into_outer()); + let edit_port = ViewPort::::new(); let mut editor = string_editor::StringEditor::new(edit_port.inner()); - compositor.push(edit_port.into_outer()); + let edit_offset_port = ViewPort::::new(); + let edit_o = GridOffset::new(edit_offset_port.inner()); + edit_port.add_observer(edit_o.clone()); + + compositor.push( + edit_offset_port + .into_outer() + // add a nice black background + .map_item(|atom| atom.map( + |a| a.add_style_back(TerminalStyle::bg_color((0,0,0)))))); + + edit_o.write().unwrap().set_offset(Vector2::new(40, 4)); + + task::spawn(async move { + for x in 0 .. 20 { + async_std::task::sleep(std::time::Duration::from_millis(15)).await; + o.write().unwrap().set_offset(Vector2::new(x as i16, x as i16)); + } + }); + /*\ <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> Event Loop