use { std::{ sync::{Arc, RwLock}, ops::Range }, cgmath::{Point2, Vector2}, crate::{ core::{ View, Observer, ObserverExt, ObserverBroadcast, InnerViewPort }, index::{IndexView}, grid::{GridView, GridWindowIterator} } }; pub struct GridOffset<V: GridView + ?Sized> { src: Option<Arc<V>>, offset: Vector2<i16>, cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = V::Item>>>> } impl<V: 'static + GridView + ?Sized> GridOffset<V> where V::Item: Default { pub fn new(port: InnerViewPort<dyn GridView<Item = V::Item>>) -> Arc<RwLock<Self>> { let offset_view = Arc::new(RwLock::new( GridOffset::<V> { src: None, offset: Vector2::new(0, 0), cast: port.get_broadcast() } )); port.set_view(Some(offset_view.clone())); offset_view } pub fn set_offset(&mut self, new_offset: Vector2<i16>) { let old_range = self.range(); self.offset = new_offset; let new_range = self.range(); if let Some(old_range) = old_range { self.cast.notify_each(GridWindowIterator::from(old_range)); } if let Some(new_range) = new_range { self.cast.notify_each(GridWindowIterator::from(new_range)); } } } impl<V: GridView + ?Sized> View for GridOffset<V> { type Msg = Point2<i16>; } impl<V: GridView + ?Sized> IndexView<Point2<i16>> for GridOffset<V> where V::Item: Default { type Item = V::Item; fn get(&self, pos: &Point2<i16>) -> Self::Item { if let Some(src) = self.src.as_ref() { src.get(&(pos - self.offset)) } else { Self::Item::default() } } fn range(&self) -> Option<Range<Point2<i16>>> { let src_range = self.src.as_ref()?.range()?; Some((src_range.start + self.offset) .. (src_range.end + self.offset)) } } impl<V: GridView + ?Sized> Observer<V> for GridOffset<V> where V::Item: Default { fn reset(&mut self, view: Option<Arc<V>>) { let old_range = self.range(); self.src = view; let new_range = self.range(); if let Some(old_range) = old_range { self.cast.notify_each(GridWindowIterator::from(old_range)); } if let Some(new_range) = new_range { self.cast.notify_each(GridWindowIterator::from(new_range)); } } fn notify(&self, msg: &Point2<i16>) { self.cast.notify(&(msg + self.offset)); } }