optimize index views with IndexArea enum to allow range based notifications
This commit is contained in:
parent
bfd27fa3fa
commit
7fdc0bf272
23 changed files with 419 additions and 548 deletions
|
@ -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>
|
||||||
|
@ -57,13 +58,15 @@ where Item: 'static
|
||||||
type Item = Item;
|
type Item = Item;
|
||||||
|
|
||||||
fn get(&self, idx: &Point2<i16>) -> Option<Self::Item> {
|
fn get(&self, idx: &Point2<i16>) -> Option<Self::Item> {
|
||||||
let chunk_idx = self.get_chunk_idx(*idx)?;
|
let chunk_idx = self.get_chunk_idx(*idx)?;
|
||||||
let chunk = self.chunks.get(&chunk_idx)?;
|
let chunk = self.chunks.get(&chunk_idx)?;
|
||||||
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) {
|
self.update_all_offsets();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Range<Point2<i16>>> for GridWindowIterator {
|
// todo: this is not perfect (e.g. diagonals are inefficient)
|
||||||
fn from(range: Range<Point2<i16>>) -> Self {
|
pub fn iter(&self) -> GridWindowIterator {
|
||||||
GridWindowIterator {
|
GridWindowIterator::from(self.range())
|
||||||
next: range.start,
|
}
|
||||||
range
|
|
||||||
}
|
pub fn range(&self) -> RangeInclusive<Point2<i16>> {
|
||||||
}
|
match self {
|
||||||
}
|
IndexArea::Empty => Point2::new(i16::MAX, i16::MAX) ..= Point2::new(i16::MIN, i16::MIN),
|
||||||
|
IndexArea::Full => panic!("range from full grid area"),
|
||||||
impl From<RangeInclusive<Point2<i16>>> for GridWindowIterator {
|
IndexArea::Set(v) =>
|
||||||
fn from(range: RangeInclusive<Point2<i16>>) -> Self {
|
Point2::new(
|
||||||
GridWindowIterator {
|
v.iter().map(|p| p.x).min().unwrap_or(0),
|
||||||
next: *range.start(),
|
v.iter().map(|p| p.y).min().unwrap_or(0)
|
||||||
range: *range.start() .. Point2::new(range.end().x+1, range.end().y+1)
|
) ..=
|
||||||
}
|
Point2::new(
|
||||||
}
|
v.iter().map(|p| p.x).max().unwrap_or(0),
|
||||||
}
|
v.iter().map(|p| p.y).max().unwrap_or(0)
|
||||||
|
),
|
||||||
impl Iterator for GridWindowIterator {
|
IndexArea::Range(r) => r.clone()
|
||||||
type Item = Point2<i16>;
|
}
|
||||||
|
}
|
||||||
fn next(&mut self) -> Option<Point2<i16>> {
|
|
||||||
if self.next.y < self.range.end.y {
|
pub fn union(self, other: IndexArea<Point2<i16>>) -> IndexArea<Point2<i16>> {
|
||||||
let next = self.next;
|
match (self, other) {
|
||||||
|
(IndexArea::Empty, a) |
|
||||||
if self.next.x+1 < self.range.end.x {
|
(a, IndexArea::Empty) => a,
|
||||||
self.next.x += 1;
|
|
||||||
} else {
|
(IndexArea::Full, _) |
|
||||||
self.next.x = self.range.start.x;
|
(_, IndexArea::Full) => IndexArea::Full,
|
||||||
self.next.y += 1;
|
|
||||||
}
|
(IndexArea::Set(mut va), IndexArea::Set(mut vb)) => {
|
||||||
|
va.extend(vb.into_iter());
|
||||||
Some(next)
|
IndexArea::Set(va)
|
||||||
} else {
|
},
|
||||||
None
|
|
||||||
|
(IndexArea::Range(r), IndexArea::Set(mut v)) |
|
||||||
|
(IndexArea::Set(mut v), IndexArea::Range(r)) => {
|
||||||
|
v.extend(GridWindowIterator::from(r));
|
||||||
|
IndexArea::Set(v)
|
||||||
|
},
|
||||||
|
|
||||||
|
(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)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
60
nested/src/grid/window_iterator.rs
Normal file
60
nested/src/grid/window_iterator.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 ]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
let new_area = self.area();
|
|
||||||
|
|
||||||
if let Some(area) = old_area { self.cast.notify_each(area); }
|
self.src_view = view;
|
||||||
if let Some(area) = new_area { self.cast.notify_each(area); }
|
|
||||||
|
self.cast.notify(&old_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 ]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
singleton::{SingletonView},
|
singleton::{SingletonView},
|
||||||
core::{
|
core::{
|
||||||
Observer, ObserverExt, ObserverBroadcast,
|
Observer, ObserverBroadcast,
|
||||||
View, ViewPort, OuterViewPort
|
View, ViewPort, OuterViewPort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 TermOutObserver {
|
||||||
|
fn send_area(&mut self, area: IndexArea<Point2<i16>>) {
|
||||||
|
match area {
|
||||||
|
IndexArea::Empty => {},
|
||||||
|
IndexArea::Full => {
|
||||||
|
let (w, h) = termion::terminal_size().unwrap();
|
||||||
|
for pos in GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(w as i16, h as i16)) {
|
||||||
|
self.dirty_pos_tx.send(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Observer<dyn TerminalView> for TermOutObserver {
|
impl Observer<dyn TerminalView> for TermOutObserver {
|
||||||
fn reset(&mut self, view: Option<Arc<dyn TerminalView>>) {
|
fn reset(&mut self, view: Option<Arc<dyn TerminalView>>) {
|
||||||
self.writer.reset();
|
self.writer.reset();
|
||||||
|
|
||||||
let (w, h) = termion::terminal_size().unwrap();
|
|
||||||
if let Some(view) = view {
|
if let Some(view) = view {
|
||||||
for pos in view.area().unwrap_or(
|
self.send_area(view.area());
|
||||||
GridWindowIterator::from(
|
|
||||||
Point2::new(0, 0) .. Point2::new(w as i16, h as i16)
|
|
||||||
).collect()
|
|
||||||
) {
|
|
||||||
self.dirty_pos_tx.send(pos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, pos: &Point2<i16>) {
|
fn notify(&mut self, area: &IndexArea<Point2<i16>>) {
|
||||||
self.dirty_pos_tx.send(*pos);
|
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))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
131
shell/src/box.rs
131
shell/src/box.rs
|
@ -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())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 ]
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
let tp = term_port.clone();
|
||||||
term_port.update();
|
async_std::task::spawn(
|
||||||
/*
|
async move {
|
||||||
if let Some(p) = pty.as_mut() {
|
loop {
|
||||||
if p.get_status() {
|
tp.update();
|
||||||
if let Some(ptybox) = ptybox.take() {
|
async_std::task::sleep(std::time::Duration::from_millis(10)).await;
|
||||||
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);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue