use { cgmath::Point2, nested::{ core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View}, sequence::{SequenceView}, index::{IndexArea, IndexView}, projection::ProjectionHelper, terminal::{TerminalAtom, TerminalView}, }, std::sync::{Arc, RwLock}, }; pub struct Plot { limit: usize, data: Arc>, cast: Arc>>, proj_helper: ProjectionHelper<(), Self>, } impl View for Plot { type Msg = IndexArea>; } impl IndexView> for Plot { type Item = TerminalAtom; fn get(&self, pt: &Point2) -> Option { if pt.y >= 0 { if let Some(cur_val) = self.data.get(&(pt.x as usize)) { if cur_val <= self.limit { if pt.y == (self.limit - cur_val) as i16 { return Some(TerminalAtom::from(if cur_val < 4 { 'o' } else if cur_val < 8 { 'O' } else { '*' })); } } if pt.x > 0 { if let Some(prev_val) = self.data.get(&((pt.x - 1) as usize)) { if (pt.y > (self.limit - prev_val) as i16 && pt.y < (self.limit - cur_val) as i16) || (pt.y < (self.limit - prev_val) as i16 && pt.y > (self.limit - cur_val) as i16) { return Some(TerminalAtom::from('.')); } } } } } None } fn area(&self) -> IndexArea> { IndexArea::Range( Point2::new(0, 0)..=Point2::new(self.data.len().unwrap_or(0) as i16, self.limit as i16), ) } } impl Plot { pub fn new( data_port: OuterViewPort>, out_port: InnerViewPort, ) -> Arc> { let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); let proj = Arc::new(RwLock::new(Plot { data: proj_helper.new_sequence_arg((), data_port, |s: &mut Self, idx| { let val = s.data.get(idx).unwrap_or(0); if val > s.limit { s.limit = val; s.cast.notify(&s.area()); } else { s.cast.notify(&IndexArea::Range( Point2::new(*idx as i16, 0)..=Point2::new(*idx as i16, s.limit as i16), )); } }), limit: 0, cast: out_port.get_broadcast(), proj_helper, })); proj.write().unwrap().proj_helper.set_proj(&proj); out_port.set_view(Some(proj.clone())); proj } }