optimize index views with IndexArea enum to allow range based notifications

This commit is contained in:
Michael Sippel 2021-11-07 07:16:33 +01:00
parent bfd27fa3fa
commit 7fdc0bf272
Signed by: senvas
GPG key ID: F96CF119C34B64A6
23 changed files with 419 additions and 548 deletions

View file

@ -1,18 +1,19 @@
use { use {
std::{ std::{
sync::Arc, sync::Arc,
cmp::max,
collections::HashMap collections::HashMap
}, },
std::sync::RwLock, std::sync::RwLock,
cgmath::{Point2, Vector2}, cgmath::{Point2, Vector2},
crate::{ crate::{
core::{ core::{
View, Observer, ObserverBroadcast, ObserverExt, View, Observer, ObserverBroadcast,
ViewPort, InnerViewPort, OuterViewPort, ViewPort, InnerViewPort, OuterViewPort,
port::UpdateTask port::UpdateTask
}, },
grid::{GridView, GridWindowIterator}, grid::{GridView, GridWindowIterator},
index::IndexView, index::{IndexArea, IndexView},
projection::ProjectionHelper projection::ProjectionHelper
} }
}; };
@ -48,7 +49,7 @@ where Item: 'static
impl<Item> View for Flatten<Item> impl<Item> View for Flatten<Item>
where Item: 'static where Item: 'static
{ {
type Msg = Point2<i16>; type Msg = IndexArea<Point2<i16>>;
} }
impl<Item> IndexView<Point2<i16>> for Flatten<Item> impl<Item> IndexView<Point2<i16>> for Flatten<Item>
@ -62,8 +63,10 @@ where Item: 'static
chunk.view.get(&(*idx - chunk.offset)) chunk.view.get(&(*idx - chunk.offset))
} }
fn area(&self) -> Option<Vec<Point2<i16>>> { fn area(&self) -> IndexArea<Point2<i16>> {
Some(GridWindowIterator::from(Point2::new(0, 0) .. self.limit).collect()) IndexArea::Range(
Point2::new(0, 0) ..= self.limit
)
} }
} }
@ -83,8 +86,10 @@ where Item: 'static
top: proj_helper.new_index_arg( top: proj_helper.new_index_arg(
Point2::new(-1, -1), Point2::new(-1, -1),
top_port, top_port,
|s: &mut Self, chunk_idx| { |s: &mut Self, chunk_area| {
s.update_chunk(*chunk_idx); for chunk_idx in chunk_area.iter() {
s.update_chunk(chunk_idx);
}
} }
), ),
chunks: HashMap::new(), chunks: HashMap::new(),
@ -104,20 +109,26 @@ where Item: 'static
let view = self.proj_helper.new_index_arg( let view = self.proj_helper.new_index_arg(
chunk_idx, chunk_idx,
chunk_port.clone(), chunk_port.clone(),
move |s: &mut Self, idx| { move |s: &mut Self, area| {
if let Some(chunk) = s.chunks.get(&chunk_idx) { if let Some(chunk) = s.chunks.get(&chunk_idx) {
if chunk.limit != chunk.view.range().end { if chunk.limit != *chunk.view.area().range().end() {
s.update_all_offsets(); s.update_all_offsets();
} }
} }
if let Some(chunk) = s.chunks.get(&chunk_idx) { if let Some(chunk) = s.chunks.get(&chunk_idx) {
s.cast.notify(&(idx + chunk.offset)); s.cast.notify(
&area.map(|pt| pt + chunk.offset)
);
} }
} }
); );
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) { if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
chunk.view = view; chunk.view = view;
self.cast.notify(
&chunk.view.area().map(|pt| pt + chunk.offset)
);
} else { } else {
self.chunks.insert( self.chunks.insert(
chunk_idx, chunk_idx,
@ -129,94 +140,91 @@ where Item: 'static
); );
} }
chunk_port.0.update();
self.update_all_offsets(); self.update_all_offsets();
chunk_port.0.update();
} else { } else {
self.proj_helper.remove_arg(&chunk_idx); self.proj_helper.remove_arg(&chunk_idx);
let mut dirty_idx = Vec::new(); if let Some(chunk) = self.chunks.remove(&chunk_idx) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
dirty_idx.extend(
GridWindowIterator::from(
Point2::new(chunk.offset.x, chunk.offset.y)
.. Point2::new(chunk.offset.x + chunk.limit.x, chunk.offset.y + chunk.limit.y))
);
}
self.chunks.remove(&chunk_idx);
self.cast.notify_each(dirty_idx);
self.update_all_offsets(); self.update_all_offsets();
} }
} }
}
/// recalculate all chunk offsets /// recalculate all chunk offsets
/// and update size of flattened grid /// and update size of flattened grid
fn update_all_offsets(&mut self) { fn update_all_offsets(&mut self) {
let mut dirty_idx = Vec::new(); let top_range = self.top.area().range();
let mut col_widths = vec![0 as i16; (top_range.end().x+1) as usize];
let mut row_heights = vec![0 as i16; (top_range.end().y+1) as usize];
let top_range = self.top.range(); for chunk_idx in GridWindowIterator::from(top_range.clone()) {
let mut col_widths = vec![0 as i16; (top_range.end.x) as usize];
let mut row_heights = vec![0 as i16; (top_range.end.y) as usize];
for chunk_idx in GridWindowIterator::from(self.top.range()) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) { if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
let lim = chunk.view.range().end; let chunk_range = chunk.view.area().range();
col_widths[chunk_idx.x as usize] = std::cmp::max(col_widths[chunk_idx.x as usize], lim.x); let lim = *chunk_range.end();
row_heights[chunk_idx.y as usize] = std::cmp::max(row_heights[chunk_idx.y as usize], lim.y);
col_widths[chunk_idx.x as usize] =
max(
col_widths[chunk_idx.x as usize],
if lim.x < 0 { 0 } else { lim.x+1 }
);
row_heights[chunk_idx.y as usize] =
max(
row_heights[chunk_idx.y as usize],
if lim.y < 0 { 0 } else { lim.y+1 }
);
} }
} }
for chunk_idx in GridWindowIterator::from(self.top.range()) { for chunk_idx in GridWindowIterator::from(top_range.clone()) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) { if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
let old_offset = chunk.offset; let old_offset = chunk.offset;
let old_limit = chunk.limit; let old_limit = chunk.limit;
chunk.limit = chunk.view.range().end; chunk.limit = *chunk.view.area().range().end();
chunk.offset = Vector2::new( chunk.offset = Vector2::new(
(0 .. chunk_idx.x as usize).map(|x| col_widths[x]).sum(), (0 .. chunk_idx.x as usize).map(|x| col_widths[x]).sum(),
(0 .. chunk_idx.y as usize).map(|y| row_heights[y]).sum() (0 .. chunk_idx.y as usize).map(|y| row_heights[y]).sum()
); );
/*
if old_offset != chunk.offset { if old_offset != chunk.offset {
dirty_idx.extend( self.cast.notify(
GridWindowIterator::from( &IndexArea::Range(
Point2::new(std::cmp::min(old_offset.x, chunk.offset.x), Point2::new(
std::cmp::min(old_offset.y, chunk.offset.y)) std::cmp::min(old_offset.x, chunk.offset.x),
.. Point2::new(std::cmp::max(old_offset.x + old_limit.x, chunk.offset.x + chunk.limit.x), std::cmp::min(old_offset.y, chunk.offset.y)
std::cmp::max(old_offset.y + old_limit.y, chunk.offset.y + chunk.limit.y))) )
..= Point2::new(
std::cmp::max(old_offset.x + old_limit.x, chunk.offset.x + chunk.limit.x),
std::cmp::max(old_offset.y + old_limit.y, chunk.offset.y + chunk.limit.y)
)
)
); );
} }
*/
} }
} }
let old_limit = self.limit; let old_limit = self.limit;
self.limit = Point2::new( self.limit = Point2::new(
(0 .. top_range.end.x as usize).map(|x| col_widths[x]).sum(), (0 ..= top_range.end().x as usize).map(|x| col_widths[x]).sum::<i16>() - 1,
(0 .. top_range.end.y as usize).map(|y| row_heights[y]).sum() (0 ..= top_range.end().y as usize).map(|y| row_heights[y]).sum::<i16>() - 1,
); );
// fixme: dirty hack to mitigate the buggy notifications, not efficien self.cast.notify(
dirty_idx.extend( &IndexArea::Range(
GridWindowIterator::from( Point2::new(0, 0) ..= Point2::new(max(self.limit.x, old_limit.x), max(self.limit.y, old_limit.y))
Point2::new(0, 0) .. Point2::new(
std::cmp::max(old_limit.x, self.limit.x),
std::cmp::max(old_limit.y, self.limit.y)
)
) )
); );
self.cast.notify_each(dirty_idx);
} }
/// given an index in the flattened sequence, /// given an index in the flattened sequence,
/// which sub-sequence does it belong to? /// which sub-sequence does it belong to?
fn get_chunk_idx(&self, glob_pos: Point2<i16>) -> Option<Point2<i16>> { fn get_chunk_idx(&self, glob_pos: Point2<i16>) -> Option<Point2<i16>> {
for chunk_idx in GridWindowIterator::from(self.top.range()) { for chunk_idx in GridWindowIterator::from(self.top.area().range()) {
if let Some(chunk) = self.chunks.get(&chunk_idx) { if let Some(chunk) = self.chunks.get(&chunk_idx) {
let chunk_range = chunk.view.range(); let end = chunk.limit + chunk.offset;
let end = chunk_range.end + chunk.offset;
if glob_pos.x < end.x && glob_pos.y < end.y { if glob_pos.x <= end.x && glob_pos.y <= end.y {
return Some(chunk_idx); return Some(chunk_idx);
} }
} }

View file

@ -1,81 +1,81 @@
use { use {
std::{ std::{
ops::{Range, RangeInclusive} ops::RangeInclusive,
cmp::{min, max}
}, },
cgmath::{Point2}, cgmath::{Point2},
crate::{ crate::index::{IndexArea, IndexView}
index::{IndexView}
}
}; };
pub mod offset;
pub mod flatten;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait GridView = IndexView<Point2<i16>>; pub trait GridView = IndexView<Point2<i16>>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item> dyn GridView<Item = Item> { pub mod offset;
pub fn range(&self) -> Range<Point2<i16>> { pub mod flatten;
if let Some(area) = self.area() { pub mod window_iterator;
Point2::new(
area.iter().map(|p| p.x).min().unwrap_or(0), pub use window_iterator::GridWindowIterator;
area.iter().map(|p| p.y).min().unwrap_or(0)
) ..
Point2::new(
area.iter().map(|p| p.x+1).max().unwrap_or(0),
area.iter().map(|p| p.y+1).max().unwrap_or(0)
)
} else {
Point2::new(i16::MIN, i16::MIN) .. Point2::new(i16::MAX, i16::MAX)
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct GridWindowIterator { impl IndexArea<Point2<i16>> {
next: Point2<i16>,
range: Range<Point2<i16>> // todo: this is not perfect (e.g. diagonals are inefficient)
pub fn iter(&self) -> GridWindowIterator {
GridWindowIterator::from(self.range())
} }
impl From<Range<Point2<i16>>> for GridWindowIterator { pub fn range(&self) -> RangeInclusive<Point2<i16>> {
fn from(range: Range<Point2<i16>>) -> Self { match self {
GridWindowIterator { IndexArea::Empty => Point2::new(i16::MAX, i16::MAX) ..= Point2::new(i16::MIN, i16::MIN),
next: range.start, IndexArea::Full => panic!("range from full grid area"),
range IndexArea::Set(v) =>
} Point2::new(
} v.iter().map(|p| p.x).min().unwrap_or(0),
} v.iter().map(|p| p.y).min().unwrap_or(0)
) ..=
impl From<RangeInclusive<Point2<i16>>> for GridWindowIterator { Point2::new(
fn from(range: RangeInclusive<Point2<i16>>) -> Self { v.iter().map(|p| p.x).max().unwrap_or(0),
GridWindowIterator { v.iter().map(|p| p.y).max().unwrap_or(0)
next: *range.start(), ),
range: *range.start() .. Point2::new(range.end().x+1, range.end().y+1) IndexArea::Range(r) => r.clone()
} }
} }
}
pub fn union(self, other: IndexArea<Point2<i16>>) -> IndexArea<Point2<i16>> {
impl Iterator for GridWindowIterator { match (self, other) {
type Item = Point2<i16>; (IndexArea::Empty, a) |
(a, IndexArea::Empty) => a,
fn next(&mut self) -> Option<Point2<i16>> {
if self.next.y < self.range.end.y { (IndexArea::Full, _) |
let next = self.next; (_, IndexArea::Full) => IndexArea::Full,
if self.next.x+1 < self.range.end.x { (IndexArea::Set(mut va), IndexArea::Set(mut vb)) => {
self.next.x += 1; va.extend(vb.into_iter());
} else { IndexArea::Set(va)
self.next.x = self.range.start.x; },
self.next.y += 1;
} (IndexArea::Range(r), IndexArea::Set(mut v)) |
(IndexArea::Set(mut v), IndexArea::Range(r)) => {
Some(next) v.extend(GridWindowIterator::from(r));
} else { IndexArea::Set(v)
None },
(IndexArea::Range(ra), IndexArea::Range(rb)) => IndexArea::Range(
Point2::new(
min(ra.start().x, rb.start().x),
min(ra.start().y, rb.start().y)
)
..=
Point2::new(
max(ra.end().x, rb.end().x),
max(ra.end().y, rb.end().y)
)
)
} }
} }
} }

View file

@ -0,0 +1,60 @@
use {
std::ops::{Range, RangeInclusive},
cgmath::{Point2}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct GridWindowIterator {
next: Point2<i16>,
range: Range<Point2<i16>>
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl From<Range<Point2<i16>>> for GridWindowIterator {
fn from(range: Range<Point2<i16>>) -> Self {
GridWindowIterator {
next: range.start,
range
}
}
}
impl From<RangeInclusive<Point2<i16>>> for GridWindowIterator {
fn from(range: RangeInclusive<Point2<i16>>) -> Self {
GridWindowIterator {
next: *range.start(),
range: *range.start() .. Point2::new(range.end().x+1, range.end().y+1)
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl Iterator for GridWindowIterator {
type Item = Point2<i16>;
fn next(&mut self) -> Option<Point2<i16>> {
if self.next.y < self.range.end.y {
if self.next.x < self.range.end.x {
let next = self.next;
if self.next.x+1 < self.range.end.x {
self.next.x += 1;
} else {
self.next.x = self.range.start.x;
self.next.y += 1;
}
Some(next)
} else {
None
}
} else {
None
}
}
}

View file

@ -13,7 +13,7 @@ use {
View, View,
InnerViewPort InnerViewPort
}, },
index::IndexView index::{IndexArea, IndexView}
} }
}; };
@ -25,7 +25,7 @@ impl<Key, Item> View for IndexBufferView<Key, Item>
where Key: Clone + Hash + Eq + Send + Sync + 'static, where Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static Item: Clone + Send + Sync + 'static
{ {
type Msg = Key; type Msg = IndexArea<Key>;
} }
impl<Key, Item> IndexView<Key> for IndexBufferView<Key, Item> impl<Key, Item> IndexView<Key> for IndexBufferView<Key, Item>
@ -38,12 +38,11 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
self.0.read().unwrap().get(key).cloned() self.0.read().unwrap().get(key).cloned()
} }
fn area(&self) -> Option<Vec<Key>> { fn area(&self) -> IndexArea<Key> {
Some(self.0.read().unwrap().keys().cloned().collect()) IndexArea::Set(self.0.read().unwrap().keys().cloned().collect())
} }
} }
pub struct IndexBuffer<Key, Item> pub struct IndexBuffer<Key, Item>
where Key: Clone + Hash + Eq + Send + Sync + 'static, where Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static Item: Clone + Send + Sync + 'static
@ -68,7 +67,7 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
pub fn insert(&mut self, key: Key, item: Item) { pub fn insert(&mut self, key: Key, item: Item) {
self.data.write().unwrap().insert(key.clone(), item); self.data.write().unwrap().insert(key.clone(), item);
self.cast.notify(&key); self.cast.notify(&IndexArea::Set(vec![ key ]));
} }
pub fn insert_iter<T>(&mut self, iter: T) pub fn insert_iter<T>(&mut self, iter: T)
@ -80,7 +79,7 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
pub fn remove(&mut self, key: Key) { pub fn remove(&mut self, key: Key) {
self.data.write().unwrap().remove(&key); self.data.write().unwrap().remove(&key);
self.cast.notify(&key); self.cast.notify(&IndexArea::Set(vec![ key ]));
} }
} }

View file

@ -14,7 +14,7 @@ pub use {
InnerViewPort, InnerViewPort,
OuterViewPort OuterViewPort
}, },
index::{IndexView} index::{IndexArea, IndexView}
} }
}; };
@ -76,7 +76,7 @@ where Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized, SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync
{ {
type Msg = Key; type Msg = IndexArea<Key>;
} }
impl<Key, DstItem, SrcView, F> IndexView<Key> for MapIndexItem<Key, DstItem, SrcView, F> impl<Key, DstItem, SrcView, F> IndexView<Key> for MapIndexItem<Key, DstItem, SrcView, F>
@ -90,7 +90,7 @@ where Key: Clone + Send + Sync,
self.src_view.get(key).as_ref().map(|item| (self.f)(key, item)) self.src_view.get(key).as_ref().map(|item| (self.f)(key, item))
} }
fn area(&self) -> Option<Vec<Key>> { fn area(&self) -> IndexArea<Key> {
self.src_view.area() self.src_view.area()
} }
} }
@ -102,15 +102,15 @@ where Key: Clone + Send + Sync,
{ {
fn reset(&mut self, view: Option<Arc<SrcView>>) { fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area(); let old_area = self.area();
self.src_view = view; self.src_view = view;
let new_area = self.area();
if let Some(area) = old_area { self.cast.notify_each(area); } self.cast.notify(&old_area);
if let Some(area) = new_area { self.cast.notify_each(area); } self.cast.notify(&self.src_view.area())
} }
fn notify(&mut self, msg: &Key) { fn notify(&mut self, area: &IndexArea<Key>) {
self.cast.notify(msg); self.cast.notify(area);
} }
} }

View file

@ -14,7 +14,7 @@ pub use {
InnerViewPort, InnerViewPort,
OuterViewPort OuterViewPort
}, },
index::{IndexView}, index::{IndexArea, IndexView},
grid::{GridView} grid::{GridView}
} }
}; };
@ -106,7 +106,7 @@ where DstKey: Clone + Send + Sync,
F1: Fn(&SrcKey) -> DstKey + Send + Sync, F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync, F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{ {
type Msg = DstKey; type Msg = IndexArea<DstKey>;
} }
impl<DstKey, SrcKey, SrcView, F1, F2> IndexView<DstKey> for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2> impl<DstKey, SrcKey, SrcView, F1, F2> IndexView<DstKey> for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
@ -122,8 +122,8 @@ where DstKey: Clone + Send + Sync,
self.src_view.get(&(self.f2)(key)?) self.src_view.get(&(self.f2)(key)?)
} }
fn area(&self) -> Option<Vec<DstKey>> { fn area(&self) -> IndexArea<DstKey> {
Some(self.src_view.area()?.iter().map(&self.f1).collect()) self.src_view.area().map(&self.f1)
} }
} }
@ -137,14 +137,12 @@ where DstKey: Clone + Send + Sync,
fn reset(&mut self, view: Option<Arc<SrcView>>) { fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area(); let old_area = self.area();
self.src_view = view; self.src_view = view;
let new_area = self.area(); self.cast.notify(&old_area);
self.cast.notify(&self.area());
if let Some(area) = old_area { self.cast.notify_each(area); }
if let Some(area) = new_area { self.cast.notify_each(area); }
} }
fn notify(&mut self, msg: &SrcKey) { fn notify(&mut self, msg: &IndexArea<SrcKey>) {
self.cast.notify(&(self.f1)(msg)); self.cast.notify(&msg.map(&self.f1));
} }
} }

View file

@ -6,7 +6,7 @@ pub mod buffer;
use { use {
std::{ std::{
sync::Arc, sync::Arc,
ops::Deref, ops::{Deref, RangeInclusive},
}, },
std::sync::RwLock, std::sync::RwLock,
crate::core::View crate::core::View
@ -14,15 +14,34 @@ use {
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait IndexView<Key> : View<Msg = Key> #[derive(Clone)]
pub enum IndexArea<Key> {
Empty,
Full,
Set(Vec<Key>),
Range(RangeInclusive<Key>),
//Procedural(Arc<dyn Fn() -> Box<dyn Iterator<Item = Key>>>)
}
impl<Key> IndexArea<Key> {
pub fn map<T>(&self, f: impl Fn(&Key) -> T) -> IndexArea<T> {
match self {
IndexArea::Empty => IndexArea::Empty,
IndexArea::Full => IndexArea::Full,
IndexArea::Set(v) => IndexArea::Set(v.iter().map(&f).collect()),
IndexArea::Range(r) => IndexArea::Range(f(&r.start()) ..= f(&r.end()))
}
}
}
pub trait IndexView<Key> : View<Msg = IndexArea<Key>>
where Key: Send + Sync { where Key: Send + Sync {
type Item; type Item;
fn get(&self, key: &Key) -> Option<Self::Item>; fn get(&self, key: &Key) -> Option<Self::Item>;
// todo: AreaIterator enum to switch between Allocated and Procedural area fn area(&self) -> IndexArea<Key> {
fn area(&self) -> Option<Vec<Key>> { IndexArea::Full
None
} }
} }
@ -38,7 +57,7 @@ where Key: Send + Sync,
self.read().unwrap().get(key) self.read().unwrap().get(key)
} }
fn area(&self) -> Option<Vec<Key>> { fn area(&self) -> IndexArea<Key> {
self.read().unwrap().area() self.read().unwrap().area()
} }
} }
@ -53,7 +72,7 @@ where Key: Send + Sync,
self.deref().get(key) self.deref().get(key)
} }
fn area(&self) -> Option<Vec<Key>> { fn area(&self) -> IndexArea<Key> {
self.deref().area() self.deref().area()
} }
} }
@ -68,17 +87,17 @@ where Key: Send + Sync,
self.as_ref()?.get(key) self.as_ref()?.get(key)
} }
fn area(&self) -> Option<Vec<Key>> { fn area(&self) -> IndexArea<Key> {
if let Some(v) = self.as_ref() { if let Some(v) = self.as_ref() {
v.area() v.area()
} else { } else {
Some(Vec::new()) IndexArea::Empty
} }
} }
} }
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
pub trait ImplIndexView : Send + Sync { pub trait ImplIndexView : Send + Sync {
type Key : Send + Sync; type Key : Send + Sync;
type Value; type Value;
@ -104,4 +123,4 @@ impl<V: ImplIndexView> IndexView<V::Key> for V {
(self as &V).area() (self as &V).area()
} }
} }
*/

View file

@ -1,94 +0,0 @@
use {
std::{
sync::{Arc}
},
std::sync::RwLock,
cgmath::Point2,
crate::{
core::{ViewPort, Observer, ObserverExt, ObserverBroadcast, InnerViewPort, OuterViewPort},
index::{ImplIndexView},
terminal::{TerminalAtom, TerminalView, TerminalStyle},
projection::{ProjectionHelper}
}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct LeveledTermView {
src: Arc<RwLock<dyn TerminalView>>,
level: usize,
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
proj_helper: ProjectionHelper<(), Self>
}
impl LeveledTermView {
pub fn new(
src: OuterViewPort<dyn TerminalView>
) -> (Arc<RwLock<Self>>, OuterViewPort<dyn TerminalView>) {
let port = ViewPort::new();
let v = Self::with_port(src, port.inner());
(v, port.into_outer())
}
pub fn with_port(
src_port: OuterViewPort<dyn TerminalView>,
dst_port: InnerViewPort<dyn TerminalView>
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(dst_port.0.update_hooks.clone());
let v = Arc::new(RwLock::new(
LeveledTermView {
src: proj_helper.new_index_arg(
(),
src_port,
|p: &mut Self, pos: &Point2<i16>| {
p.cast.notify(pos);
}),
level: 0,
cast: dst_port.get_broadcast(),
proj_helper
}
));
v.write().unwrap().proj_helper.set_proj(&v);
dst_port.set_view(Some(v.clone()));
v
}
pub fn set_level(&mut self, l: usize) {
if self.level != l {
self.level = l;
// update complete area
if let Some(a) = self.src.area() {
self.cast.notify_each(a);
}
}
}
}
impl ImplIndexView for LeveledTermView {
type Key = Point2<i16>;
type Value = TerminalAtom;
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
self.src.get(pos).map(
|a| a.add_style_front(
if self.level > 1 {
TerminalStyle::bold(true)
.add(TerminalStyle::bg_color((0, 0, 0)))
} else if self.level > 0 {
TerminalStyle::bg_color((40, 40, 40))
} else {
TerminalStyle::bold(false)
})
)
}
fn area(&self) -> Option<Vec<Point2<i16>>> {
self.src.area()
}
}

View file

@ -15,7 +15,6 @@ pub mod list;
pub mod tree_nav; pub mod tree_nav;
pub mod string_editor; pub mod string_editor;
pub mod leveled_term_view;
pub mod bimap; pub mod bimap;

View file

@ -3,22 +3,9 @@ use {
termion::event::{Event, Key}, termion::event::{Event, Key},
crate::{ crate::{
core::{ core::{
View,
ViewPort, ViewPort,
OuterViewPort, OuterViewPort,
InnerViewPort,
ObserverBroadcast,
Observer,
ObserverExt,
context::{
ReprTree,
Object,
MorphismType,
MorphismMode,
Context
}
}, },
projection::ProjectionHelper,
singleton::{SingletonView, SingletonBuffer}, singleton::{SingletonView, SingletonBuffer},
sequence::{SequenceView}, sequence::{SequenceView},
vec::{VecBuffer}, vec::{VecBuffer},
@ -30,7 +17,6 @@ use {
TerminalEditorResult, TerminalEditorResult,
make_label make_label
}, },
leveled_term_view::LeveledTermView,
list::{SExprView, ListDecoration, ListCursor, ListCursorMode, editor_view::{ListEditorView, ListEditorViewSegment}}, list::{SExprView, ListDecoration, ListCursor, ListCursorMode, editor_view::{ListEditorView, ListEditorViewSegment}},
tree_nav::{TreeCursor, TreeNav, TreeNavResult, TerminalTreeEditor} tree_nav::{TreeCursor, TreeNav, TreeNavResult, TerminalTreeEditor}
} }
@ -61,6 +47,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
style: ListEditorStyle, style: ListEditorStyle,
level: usize, level: usize,
cur_dist: Arc<RwLock<usize>>,
} }
impl<ItemEditor, FnMakeItemEditor> TreeNav for ListEditor<ItemEditor, FnMakeItemEditor> impl<ItemEditor, FnMakeItemEditor> TreeNav for ListEditor<ItemEditor, FnMakeItemEditor>
@ -326,6 +313,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
tree_addr: vec![] tree_addr: vec![]
} }
); );
*self.cur_dist.write().unwrap() += 1;
} }
} }
TreeNavResult::Continue TreeNavResult::Continue
@ -586,7 +574,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
} }
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor> impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static, where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>> FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>
{ {
pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> { pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
@ -596,32 +584,39 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
self.data_port.outer().to_sequence().map(|ed| ed.read().unwrap().get_term_view()), self.data_port.outer().to_sequence().map(|ed| ed.read().unwrap().get_term_view()),
segment_view_port.inner() segment_view_port.inner()
); );
segment_view_port.into_outer() segment_view_port.into_outer()
.map( .map(
|segment| match segment { move |segment| {
let cursor_col = (90, 60, 200);
match segment {
ListEditorViewSegment::InsertCursor => ListEditorViewSegment::InsertCursor =>
make_label("|") make_label("|")
.map_item( .map_item(
|_pt, atom| move |_pt, atom|
atom.add_style_back(TerminalStyle::fg_color((90,60,200))) atom.add_style_back(TerminalStyle::fg_color(cursor_col))
//.add_style_back(TerminalStyle::bg_color((0,0,0)))
.add_style_back(TerminalStyle::bold(true)) .add_style_back(TerminalStyle::bold(true))
), ),
ListEditorViewSegment::Select(sub_view) => ListEditorViewSegment::Select(sub_view) =>
sub_view.map_item( sub_view.map_item(
|_pt, atom| move |_pt, atom| {
atom.add_style_front(TerminalStyle::bg_color((90,60,200))) let old_col = atom.style.bg_color.unwrap_or(cursor_col);
atom.add_style_front(TerminalStyle::bg_color(((old_col.0 as f32 * 0.4) as u8, (old_col.1 as f32 * 0.4) as u8, (old_col.2 as f32 * 0.4) as u8)))
}
), ),
ListEditorViewSegment::Modify(sub_view) => { ListEditorViewSegment::Modify(sub_view) => {
sub_view.clone().map_item( sub_view.clone().map_item(
|_pt, atom| move |_pt, atom| {
atom.add_style_back(TerminalStyle::bg_color((22,15,50))) let old_col = atom.style.bg_color.unwrap_or(cursor_col);
atom.add_style_front(TerminalStyle::bg_color(((old_col.0 as f32 * 0.4) as u8, (old_col.1 as f32 * 0.4) as u8, (old_col.2 as f32 * 0.4) as u8)))
}
//.add_style_back(TerminalStyle::bold(true)) //.add_style_back(TerminalStyle::bold(true))
) )
}, },
ListEditorViewSegment::View(sub_view) => ListEditorViewSegment::View(sub_view) =>
sub_view.clone() sub_view.clone()
} }
}
) )
} }
@ -644,6 +639,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
self.get_seg_seq_view() self.get_seg_seq_view()
.decorate("\"", "\"", "", 1) .decorate("\"", "\"", "", 1)
.to_grid_horizontal() .to_grid_horizontal()
.flatten() .flatten()
} }
@ -681,7 +677,8 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
style, style,
make_item_editor, make_item_editor,
level: 0 level: 0,
cur_dist: Arc::new(RwLock::new(0))
}; };
le.set_style(style); le.set_style(style);
le le

View file

@ -3,6 +3,7 @@ use {
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort}, core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
projection::ProjectionHelper, projection::ProjectionHelper,
sequence::SequenceView, sequence::SequenceView,
index::{IndexArea},
terminal::{make_label, TerminalStyle, TerminalView}, terminal::{make_label, TerminalStyle, TerminalView},
}, },
cgmath::Point2, cgmath::Point2,
@ -141,19 +142,16 @@ pub struct VerticalSexprDecorator {
} }
impl View for VerticalSexprDecorator { impl View for VerticalSexprDecorator {
type Msg = Point2<i16>; type Msg = IndexArea<Point2<i16>>;
} }
impl IndexView<Point2<i16>> for VerticalSexprDecorator { impl IndexView<Point2<i16>> for VerticalSexprDecorator {
type Item = OuterViewPort<dyn TerminalView>; type Item = OuterViewPort<dyn TerminalView>;
fn area(&self) -> Option<Vec<Point2<i16>>> { fn area(&self) -> IndexArea<Point2<i16>> {
let mut area = (0..self.items.len()?) IndexArea::Range(
.map(|i| Point2::new(1 as i16, i as i16)) Point2::new(0, 0) ..= Point2::new(2, std::cmp::max(self.items.len().unwrap() as i16 - 1, 0))
.collect::<Vec<_>>(); )
area.push(Point2::new(0, 0));
area.push(Point2::new(2, self.items.len()? as i16 - 1));
Some(area)
} }
fn get(&self, pt: &Point2<i16>) -> Option<Self::Item> { fn get(&self, pt: &Point2<i16>) -> Option<Self::Item> {
@ -218,9 +216,11 @@ impl VerticalSexprDecorator {
opening_port: make_label(opening), opening_port: make_label(opening),
closing_port: make_label(closing), closing_port: make_label(closing),
items: proj_helper.new_sequence_arg((), items_port, |s: &mut Self, item_idx| { items: proj_helper.new_sequence_arg((), items_port, |s: &mut Self, item_idx| {
s.cast.notify(&Point2::new(1, *item_idx as i16)); s.cast.notify(
s.cast.notify(&Point2::new(2, *item_idx as i16 - 1)); &IndexArea::Range(
s.cast.notify(&Point2::new(2, *item_idx as i16)); Point2::new(0, *item_idx as i16) ..= Point2::new(2, *item_idx as i16)
)
);
}), }),
list_style: TerminalStyle::fg_color(match level { list_style: TerminalStyle::fg_color(match level {
0 => (200, 120, 10), 0 => (200, 120, 10),

View file

@ -16,12 +16,13 @@ use {
channel::{ channel::{
ChannelSender, ChannelReceiver, ChannelSender, ChannelReceiver,
ChannelData, ChannelData,
set_channel set_channel,
queue_channel
} }
}, },
singleton::{SingletonView}, singleton::{SingletonView},
sequence::{SequenceView}, sequence::{SequenceView},
index::{IndexView} index::{IndexArea, IndexView}
} }
}; };
@ -75,13 +76,13 @@ where ArgKey: Clone + Hash + Eq,
port.get_view_arc() port.get_view_arc()
} }
pub fn new_index_arg<Key: Hash + Eq + Clone + Send + Sync + std::fmt::Debug + 'static, Item: 'static>( pub fn new_index_arg<Key: Clone + Send + Sync + 'static, Item: 'static>(
&mut self, &mut self,
arg_key: ArgKey, arg_key: ArgKey,
port: OuterViewPort<dyn IndexView<Key, Item = Item>>, port: OuterViewPort<dyn IndexView<Key, Item = Item>>,
notify: impl Fn(&mut P, &Key) + Send + Sync + 'static notify: impl Fn(&mut P, &IndexArea<Key>) + Send + Sync + 'static
) -> Arc<RwLock<Option<Arc<dyn IndexView<Key, Item = Item>>>>> { ) -> Arc<RwLock<Option<Arc<dyn IndexView<Key, Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel())); port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, queue_channel()));
port.get_view_arc() port.get_view_arc()
} }
@ -96,7 +97,7 @@ where ArgKey: Clone + Hash + Eq,
(tx, rx): (ChannelSender<D>, ChannelReceiver<D>) (tx, rx): (ChannelSender<D>, ChannelReceiver<D>)
) )
-> Arc<RwLock<ProjectionArg<P, V, D>>> -> Arc<RwLock<ProjectionArg<P, V, D>>>
where V::Msg: Send + Sync + std::fmt::Debug, where V::Msg: Send + Sync,
D::IntoIter: Send + Sync + 'static D::IntoIter: Send + Sync + 'static
{ {
self.remove_arg(&arg_key); self.remove_arg(&arg_key);
@ -151,8 +152,7 @@ impl<P, V, D> UpdateTask for ProjectionArg<P, V, D>
where P: Send + Sync + 'static, where P: Send + Sync + 'static,
V: View + ?Sized, V: View + ?Sized,
D: ChannelData<Item = V::Msg>, D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync, D::IntoIter: Send + Sync
V::Msg: std::fmt::Debug
{ {
fn update(&self) { fn update(&self) {
if let Some(p) = self.proj.read().unwrap().upgrade() { if let Some(p) = self.proj.read().unwrap().upgrade() {
@ -175,8 +175,7 @@ impl<P, V, D> UpdateTask for RwLock<ProjectionArg<P, V, D>>
where P: Send + Sync + 'static, where P: Send + Sync + 'static,
V: View + ?Sized, V: View + ?Sized,
D: ChannelData<Item = V::Msg>, D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync, D::IntoIter: Send + Sync
V::Msg: std::fmt::Debug
{ {
fn update(&self) { fn update(&self) {
self.read().unwrap().update(); self.read().unwrap().update();
@ -225,19 +224,18 @@ where P: Send + Sync + 'static,
impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>> for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D> impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>> for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D>
where P: Send + Sync + 'static, where P: Send + Sync + 'static,
Key: Clone + Send + Sync, Key: Clone + Send + Sync,
D: ChannelData<Item = Key>, D: ChannelData<Item = IndexArea<Key>>,
D::IntoIter: Send + Sync D::IntoIter: Send + Sync
{ {
fn reset(&mut self, new_src: Option<Arc<dyn IndexView<Key, Item = Item>>>) { fn reset(&mut self, new_src: Option<Arc<dyn IndexView<Key, Item = Item>>>) {
let old_area = self.src.area(); let old_area = self.src.area();
self.src = new_src; self.src = new_src;
let new_area = self.src.area();
if let Some(area) = old_area { self.notify_each(area); } self.notify(&old_area);
if let Some(area) = new_area { self.notify_each(area); } self.notify(&self.src.area())
} }
fn notify(&mut self, msg: &Key) { fn notify(&mut self, msg: &IndexArea<Key>) {
self.tx.send(msg.clone()); self.tx.send(msg.clone());
} }
} }

View file

@ -5,11 +5,11 @@ use {
std::sync::RwLock, std::sync::RwLock,
crate::{ crate::{
core::{ core::{
View, Observer, ObserverExt, ObserverBroadcast, View, Observer, ObserverBroadcast,
ViewPort, InnerViewPort, OuterViewPort ViewPort, InnerViewPort, OuterViewPort
}, },
sequence::SequenceView, sequence::SequenceView,
index::IndexView, index::{IndexArea, IndexView},
grid::GridView grid::GridView
} }
}; };
@ -56,7 +56,7 @@ impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
impl<SrcView> View for Sequence2Index<SrcView> impl<SrcView> View for Sequence2Index<SrcView>
where SrcView: SequenceView + ?Sized + 'static { where SrcView: SequenceView + ?Sized + 'static {
type Msg = usize; type Msg = IndexArea<usize>;
} }
impl<SrcView> IndexView<usize> for Sequence2Index<SrcView> impl<SrcView> IndexView<usize> for Sequence2Index<SrcView>
@ -67,8 +67,16 @@ where SrcView: SequenceView + ?Sized + 'static {
self.src_view.get(key) self.src_view.get(key)
} }
fn area(&self) -> Option<Vec<usize>> { fn area(&self) -> IndexArea<usize> {
Some((0 .. self.src_view.len()?).collect()) if let Some(len) = self.src_view.len() {
if len > 0 {
IndexArea::Range(0 ..= len-1)
} else {
IndexArea::Empty
}
} else {
IndexArea::Full
}
} }
} }
@ -77,14 +85,13 @@ where SrcView: SequenceView + ?Sized + 'static {
fn reset(&mut self, view: Option<Arc<SrcView>>) { fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area(); let old_area = self.area();
self.src_view = view; self.src_view = view;
let new_area = self.area();
if let Some(area) = old_area { self.cast.notify_each(area); } self.cast.notify(&old_area);
if let Some(area) = new_area { self.cast.notify_each(area); } self.cast.notify(&self.area());
} }
fn notify(&mut self, msg: &usize) { fn notify(&mut self, idx: &usize) {
self.cast.notify(msg); self.cast.notify(&IndexArea::Set(vec![ *idx ]));
} }
} }

View file

@ -4,7 +4,7 @@ use {
crate::{ crate::{
singleton::{SingletonView}, singleton::{SingletonView},
core::{ core::{
Observer, ObserverExt, ObserverBroadcast, Observer, ObserverBroadcast,
View, ViewPort, OuterViewPort View, ViewPort, OuterViewPort
} }
} }

View file

@ -3,10 +3,10 @@ use {
std::sync::RwLock, std::sync::RwLock,
crate::{ crate::{
singleton::{SingletonView}, singleton::{SingletonView},
index::{IndexView}, index::{IndexArea, IndexView},
grid::{GridView}, grid::{GridView},
core::{ core::{
Observer, ObserverExt, ObserverBroadcast, Observer, ObserverBroadcast,
View, ViewPort, OuterViewPort View, ViewPort, OuterViewPort
} }
} }
@ -52,7 +52,7 @@ where SrcView: SingletonView + ?Sized
impl<SrcView> View for Singleton2Index<SrcView> impl<SrcView> View for Singleton2Index<SrcView>
where SrcView: SingletonView + ?Sized where SrcView: SingletonView + ?Sized
{ {
type Msg = (); type Msg = IndexArea<()>;
} }
impl<SrcView> IndexView<()> for Singleton2Index<SrcView> impl<SrcView> IndexView<()> for Singleton2Index<SrcView>
@ -60,9 +60,10 @@ where SrcView: SingletonView + ?Sized
{ {
type Item = SrcView::Item; type Item = SrcView::Item;
fn area(&self) -> Option<Vec<()>> { fn area(&self) -> IndexArea<()> {
Some(vec![()]) IndexArea::Full
} }
fn get(&self, _msg: &()) -> Option<Self::Item> { fn get(&self, _msg: &()) -> Option<Self::Item> {
Some(self.src_view.as_ref().unwrap().get()) Some(self.src_view.as_ref().unwrap().get())
} }
@ -75,11 +76,11 @@ where SrcView: SingletonView + ?Sized
{ {
fn reset(&mut self, view: Option<Arc<SrcView>>) { fn reset(&mut self, view: Option<Arc<SrcView>>) {
self.src_view = view; self.src_view = view;
self.cast.notify(&()); self.cast.notify(&IndexArea::Full);
} }
fn notify(&mut self, msg: &()) { fn notify(&mut self, _: &()) {
self.cast.notify(msg); self.cast.notify(&IndexArea::Full);
} }
} }

View file

@ -6,7 +6,6 @@ use {
core::{ViewPort, OuterViewPort}, core::{ViewPort, OuterViewPort},
singleton::{SingletonView, SingletonBuffer}, singleton::{SingletonView, SingletonBuffer},
sequence::{SequenceView}, sequence::{SequenceView},
vec::VecBuffer,
terminal::{TerminalView, TerminalStyle, TerminalEvent, TerminalEditor, TerminalEditorResult}, terminal::{TerminalView, TerminalStyle, TerminalEvent, TerminalEditor, TerminalEditorResult},
list::{ListEditor, sexpr::ListDecoration}, list::{ListEditor, sexpr::ListDecoration},
tree_nav::{TreeNav, TreeNavResult, TreeCursor} tree_nav::{TreeNav, TreeNavResult, TreeCursor}

View file

@ -5,8 +5,8 @@ use {
std::sync::RwLock, std::sync::RwLock,
cgmath::Point2, cgmath::Point2,
crate::{ crate::{
core::{InnerViewPort, OuterViewPort, Observer, ObserverBroadcast}, core::{InnerViewPort, OuterViewPort, View, Observer, ObserverBroadcast},
index::{ImplIndexView}, index::{IndexArea, IndexView},
terminal::{TerminalAtom, TerminalView}, terminal::{TerminalAtom, TerminalView},
projection::ProjectionHelper projection::ProjectionHelper
} }
@ -46,8 +46,8 @@ impl TerminalCompositor {
self.proj_helper.new_index_arg( self.proj_helper.new_index_arg(
idx, idx,
v, v,
|s: &mut Self, pos| { |s: &mut Self, area| {
s.cast.notify(pos); s.cast.notify(area);
} }
) )
); );
@ -56,9 +56,12 @@ impl TerminalCompositor {
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl ImplIndexView for TerminalCompositor { impl View for TerminalCompositor {
type Key = Point2<i16>; type Msg = IndexArea<Point2<i16>>;
type Value = TerminalAtom; }
impl IndexView<Point2<i16>> for TerminalCompositor {
type Item = TerminalAtom;
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> { fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
let mut atom = None; let mut atom = None;
@ -74,21 +77,11 @@ impl ImplIndexView for TerminalCompositor {
atom atom
} }
fn area(&self) -> Option<Vec<Point2<i16>>> { fn area(&self) -> IndexArea<Point2<i16>> {
let mut area = Some(Vec::new()); let mut area = IndexArea::Empty;
for layer in self.layers.iter() { for layer in self.layers.iter() {
if let ( area = area.union(layer.area());
Some(mut new_area),
Some(area)
) = (
layer.area(),
area.as_mut()
) {
area.append(&mut new_area);
} else {
area = None;
}
} }
area area

View file

@ -27,6 +27,7 @@ use {
set_channel set_channel
} }
}, },
index::{IndexArea},
grid::{GridWindowIterator} grid::{GridWindowIterator}
}, },
super::{ super::{
@ -119,24 +120,40 @@ struct TermOutObserver {
writer: Arc<TermOutWriter> writer: Arc<TermOutWriter>
} }
impl Observer<dyn TerminalView> for TermOutObserver { impl TermOutObserver {
fn reset(&mut self, view: Option<Arc<dyn TerminalView>>) { fn send_area(&mut self, area: IndexArea<Point2<i16>>) {
self.writer.reset(); match area {
IndexArea::Empty => {},
IndexArea::Full => {
let (w, h) = termion::terminal_size().unwrap(); let (w, h) = termion::terminal_size().unwrap();
if let Some(view) = view { for pos in GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(w as i16, h as i16)) {
for pos in view.area().unwrap_or( self.dirty_pos_tx.send(pos);
GridWindowIterator::from( }
Point2::new(0, 0) .. Point2::new(w as i16, h as i16) }
).collect() IndexArea::Range(r) => {
) { for pos in GridWindowIterator::from(r) {
self.dirty_pos_tx.send(pos);
}
}
IndexArea::Set(v) => {
for pos in v {
self.dirty_pos_tx.send(pos); self.dirty_pos_tx.send(pos);
} }
} }
} }
}
}
fn notify(&mut self, pos: &Point2<i16>) { impl Observer<dyn TerminalView> for TermOutObserver {
self.dirty_pos_tx.send(*pos); fn reset(&mut self, view: Option<Arc<dyn TerminalView>>) {
self.writer.reset();
if let Some(view) = view {
self.send_area(view.area());
}
}
fn notify(&mut self, area: &IndexArea<Point2<i16>>) {
self.send_area(area.clone());
} }
} }
@ -166,10 +183,24 @@ impl TermOutWriter {
// draw atoms until view port is destroyed // draw atoms until view port is destroyed
while let Some(dirty_pos) = self.dirty_pos_rx.recv().await { while let Some(dirty_pos) = self.dirty_pos_rx.recv().await {
let (w, h) = termion::terminal_size().unwrap();
if let Some(view) = self.view.read().unwrap().as_ref() { if let Some(view) = self.view.read().unwrap().as_ref() {
let mut out = self.out.write().unwrap(); let mut out = self.out.write().unwrap();
for pos in dirty_pos.into_iter().filter(|p| p.x >= 0 && p.y >= 0) { let d = dirty_pos.into_iter().filter(|p| p.x >= 0 && p.y >= 0 && p.x < w as i16 && p.y < w as i16);//.collect::<Vec<_>>();
/*
d.sort_by(|a,b| {
if a.y < b.y {
std::cmp::Ordering::Less
} else if a.y == b.y {
a.x.cmp(&b.x)
} else {
std::cmp::Ordering::Greater
}
});
*/
for pos in d {
if pos != cur_pos { if pos != cur_pos {
write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?; write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?;
} }

View file

@ -5,5 +5,5 @@
# to the user in the error, instead of "error: invalid channel name '[toolchain]'". # to the user in the error, instead of "error: invalid channel name '[toolchain]'".
[toolchain] [toolchain]
channel = "nightly-2021-09-29" channel = "nightly-2021-10-26"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"] components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -13,7 +13,7 @@ use{
ObserverBroadcast, ObserverBroadcast,
context::{ReprTree, Object, MorphismType, MorphismMode, Context}, context::{ReprTree, Object, MorphismType, MorphismMode, Context},
port::{UpdateTask}}, port::{UpdateTask}},
index::{IndexView}, index::{IndexArea, IndexView},
grid::{GridWindowIterator}, grid::{GridWindowIterator},
terminal::{ terminal::{
Terminal, Terminal,
@ -57,14 +57,19 @@ impl AsciiBox {
if self.extent != new_extent { if self.extent != new_extent {
let old_extent = self.extent; let old_extent = self.extent;
self.extent = new_extent; self.extent = new_extent;
self.notify_each(GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(2+std::cmp::max(old_extent.x, new_extent.x), 2+std::cmp::max(old_extent.y, new_extent.y)))); self.cast.notify(
&IndexArea::Range(
Point2::new(0, 0) ..=
Point2::new(
1+std::cmp::max(old_extent.x, new_extent.x),
1+std::cmp::max(old_extent.y, new_extent.y))));
} }
} }
pub fn fit_content(&mut self) { pub fn fit_content(&mut self) {
if let Some(c) = self.content.as_ref() { if let Some(c) = self.content.as_ref() {
let p = c.range().end; let p = *c.area().range().end();
self.resize(Vector2::new(p.x, p.y)); self.resize(Vector2::new(p.x+1, p.y+1));
} else { } else {
self.resize(Vector2::new(0, 0)); self.resize(Vector2::new(0, 0));
} }
@ -74,17 +79,17 @@ impl AsciiBox {
impl Observer<dyn TerminalView> for AsciiBox { impl Observer<dyn TerminalView> for AsciiBox {
fn reset(&mut self, new_content: Option<Arc<dyn TerminalView>>) { fn reset(&mut self, new_content: Option<Arc<dyn TerminalView>>) {
self.content = new_content; self.content = new_content;
self.notify_each(GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(self.extent.x+2, self.extent.y+2))); self.fit_content();
} }
fn notify(&mut self, pt: &Point2<i16>) { fn notify(&mut self, area: &IndexArea<Point2<i16>>) {
self.cast.notify(&(pt + Vector2::new(1, 1))); self.cast.notify(&area.map(|pt| pt + Vector2::new(1, 1)));
self.fit_content(); self.fit_content();
} }
} }
impl View for AsciiBox { impl View for AsciiBox {
type Msg = Point2<i16>; type Msg = IndexArea<Point2<i16>>;
} }
impl IndexView<Point2<i16>> for AsciiBox { impl IndexView<Point2<i16>> for AsciiBox {
@ -114,19 +119,19 @@ impl IndexView<Point2<i16>> for AsciiBox {
None None
} }
} else if } else if
pt.x > 0 &&
pt.y > 0 &&
pt.x < self.extent.x+1 && pt.x < self.extent.x+1 &&
pt.y < self.extent.y+1 pt.y < self.extent.y+1
{ {
self.content.get(&(pt - Vector2::new(1, 1))) Some(self.content.get(&(pt - Vector2::new(1, 1))).unwrap_or(TerminalAtom::from(' ')))
} else { } else {
None None
} }
} }
fn area(&self) -> Option<Vec<Point2<i16>>> { fn area(&self) -> IndexArea<Point2<i16>> {
Some(GridWindowIterator::from( IndexArea::Range(Point2::new(0, 0) ..= Point2::new(1,1)+self.extent)
Point2::new(0, 0) .. Point2::new(self.extent.x+2, self.extent.y+2) }
).collect())
} }
}

View file

@ -1,131 +0,0 @@
use{
std::sync::{Arc, RwLock},
cgmath::{Point2, Vector2},
nested::{
core::{
View,
ViewPort,
InnerViewPort,
OuterViewPort,
Observer,
ObserverExt,
ObserverBroadcast,
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
port::{UpdateTask}},
index::{IndexView},
grid::{GridWindowIterator},
terminal::{
Terminal,
TerminalStyle,
TerminalAtom,
TerminalCompositor,
TerminalEvent,
make_label,
TerminalView,
TerminalEditor},
}
};
pub struct AsciiBox {
content: Option<Arc<dyn TerminalView>>,
extent: Vector2<i16>,
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
}
impl AsciiBox {
pub fn new(
extent: Vector2<i16>,
content_port: OuterViewPort<dyn TerminalView>,
output_port: InnerViewPort<dyn TerminalView>
) -> Arc<RwLock<Self>> {
let ascii_box = Arc::new(RwLock::new(AsciiBox {
content: None,
extent,
cast: output_port.get_broadcast()
}));
output_port.0.update_hooks.write().unwrap().push(Arc::new(content_port.0.clone()));
output_port.set_view(Some(ascii_box.clone()));
content_port.add_observer(ascii_box.clone());
ascii_box
}
pub fn resize(&mut self, new_extent: Vector2<i16>) {
if self.extent != new_extent {
let old_extent = self.extent;
self.extent = new_extent;
self.notify_each(GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(2+std::cmp::max(old_extent.x, new_extent.x), 2+std::cmp::max(old_extent.y, new_extent.y))));
}
}
pub fn fit_content(&mut self) {
if let Some(c) = self.content.as_ref() {
let p = c.range().end;
self.resize(Vector2::new(p.x, p.y));
} else {
self.resize(Vector2::new(0, 0));
}
}
}
impl Observer<dyn TerminalView> for AsciiBox {
fn reset(&mut self, new_content: Option<Arc<dyn TerminalView>>) {
self.content = new_content;
self.notify_each(GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(self.extent.x+2, self.extent.y+2)));
}
fn notify(&mut self, pt: &Point2<i16>) {
self.cast.notify(&(pt + Vector2::new(1, 1)));
}
}
impl View for AsciiBox {
type Msg = Point2<i16>;
}
impl IndexView<Point2<i16>> for AsciiBox {
type Item = TerminalAtom;
fn get(&self, pt: &Point2<i16>) -> Option<TerminalAtom> {
if pt.x == 0 || pt.x == self.extent.x+1 {
// vertical line
if pt.y == 0 && pt.x == 0 {
Some(TerminalAtom::from('╭'))
} else if pt.y == 0 && pt.x == self.extent.x+1 {
Some(TerminalAtom::from('╮'))
} else if pt.y > 0 && pt.y < self.extent.y+1 {
Some(TerminalAtom::from('│'))
} else if pt.y == self.extent.y+1 && pt.x == 0 {
Some(TerminalAtom::from('╰'))
} else if pt.y == self.extent.y+1 && pt.x == self.extent.x+1 {
Some(TerminalAtom::from('╯'))
} else {
None
}
} else if pt.y == 0 || pt.y == self.extent.y+1 {
// horizontal line
if pt.x > 0 && pt.x < self.extent.x+1 {
Some(TerminalAtom::from('─'))
} else {
None
}
} else if
pt.x < self.extent.x+1 &&
pt.y < self.extent.y+1
{
self.content.get(&(pt - Vector2::new(1, 1)))
} else {
None
}
}
fn area(&self) -> Option<Vec<Point2<i16>>> {
Some(GridWindowIterator::from(
Point2::new(0, 0) .. Point2::new(self.extent.x+2, self.extent.y+2)
).collect())
}
}

View file

@ -21,7 +21,7 @@ use{
ObserverBroadcast, ObserverBroadcast,
context::{ReprTree, Object, MorphismType, MorphismMode, Context}, context::{ReprTree, Object, MorphismType, MorphismMode, Context},
port::{UpdateTask}}, port::{UpdateTask}},
index::{IndexView}, index::{IndexView, IndexArea},
grid::{GridWindowIterator}, grid::{GridWindowIterator},
sequence::{SequenceView, SequenceViewExt}, sequence::{SequenceView, SequenceViewExt},
vec::{VecBuffer}, vec::{VecBuffer},
@ -44,6 +44,24 @@ use{
} }
}; };
struct TestView {}
impl View for TestView {
type Msg = IndexArea<Point2<i16>>;
}
impl IndexView<Point2<i16>> for TestView {
type Item = TerminalAtom;
fn get(&self, pt: &Point2<i16>) -> Option<TerminalAtom> {
Some(TerminalAtom::from('.'))
}
fn area(&self) -> IndexArea<Point2<i16>> {
IndexArea::Full
}
}
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let term_port = ViewPort::new(); let term_port = ViewPort::new();
@ -99,35 +117,22 @@ async fn main() {
tree_addr: vec![ 0 ] tree_addr: vec![ 0 ]
}); });
let tp = term_port.clone();
async_std::task::spawn(
async move {
loop { loop {
term_port.update(); tp.update();
/* async_std::task::sleep(std::time::Duration::from_millis(10)).await;
if let Some(p) = pty.as_mut() {
if p.get_status() {
if let Some(ptybox) = ptybox.take() {
ptybox.write().unwrap().fit_content();
}
pty = None;
process_list_editor.up();
} }
} }
*/ );
term_port.update();
loop {
let ev = term.next_event().await; let ev = term.next_event().await;
/*
if let Some(pty) = pty.as_mut() {
pty.handle_terminal_event(&ev);
} else {
*/
match ev { match ev {
TerminalEvent::Resize(new_size) => { TerminalEvent::Resize(new_size) => {
cur_size.set(new_size); cur_size.set(new_size);
term_port.inner().get_broadcast().notify_each( term_port.inner().get_broadcast().notify(&IndexArea::Full);
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('c'))) |
TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) | TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
@ -157,27 +162,7 @@ async fn main() {
process_list_editor.goto_end(); process_list_editor.goto_end();
} }
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => { TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
//let mut output_port = ViewPort::new();
process_list_editor.get_item().unwrap().write().unwrap().launch_pty2(); process_list_editor.get_item().unwrap().write().unwrap().launch_pty2();
/*
let box_port = ViewPort::new();
let test_box = AsciiBox::new(
Vector2::new(80, 25),
output_port.outer()
.map_item(|_,a| a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))),
box_port.inner()
);
ptybox = Some(test_box.clone());
table_buf.remove(Point2::new(0, y-1));
let mut p = box_port.outer().map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100))) .offset(Vector2::new(0, -1));
table_port.update_hooks.write().unwrap().push(Arc::new(p.clone().0));
y += 1;
table_buf.insert(Point2::new(0, y), p.clone());
*/
} }
ev => { ev => {
@ -229,7 +214,8 @@ async fn main() {
} }
} }
//drop(term); drop(term);
drop(term_port);
} }
); );

View file

@ -134,10 +134,6 @@ impl ProcessLauncher {
pub fn launch_pty2(&mut self) { pub fn launch_pty2(&mut self) {
self.launch_pty(self.pty_port.inner()); self.launch_pty(self.pty_port.inner());
//self.ptybox.write().unwrap().fit_content();
//let mut p =
//table_port.update_hooks.write().unwrap().push(Arc::new(p.clone().0));
} }
pub fn launch_pty(&mut self, port: InnerViewPort<dyn TerminalView>) -> Option<crate::pty::PTY> { pub fn launch_pty(&mut self, port: InnerViewPort<dyn TerminalView>) -> Option<crate::pty::PTY> {