improve ProjectionArg, ProjectionHelper
This commit is contained in:
parent
8d73e67615
commit
a2d5ea7707
3 changed files with 127 additions and 72 deletions
|
@ -1,20 +1,25 @@
|
||||||
use {
|
use {
|
||||||
std::sync::{Arc, RwLock},
|
std::{
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
collections::HashSet
|
||||||
|
},
|
||||||
cgmath::Point2,
|
cgmath::Point2,
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, Observer, ObserverExt, ObserverBroadcast, InnerViewPort, OuterViewPort},
|
core::{ViewPort, Observer, ObserverExt, ObserverBroadcast, InnerViewPort, OuterViewPort},
|
||||||
index::{ImplIndexView},
|
index::{ImplIndexView},
|
||||||
terminal::{TerminalAtom, TerminalView, TerminalStyle},
|
terminal::{TerminalAtom, TerminalView, TerminalStyle},
|
||||||
projection::ProjectionArg
|
projection::{ProjectionHelper, ProjectionArg}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct LeveledTermView {
|
pub struct LeveledTermView {
|
||||||
src: Arc<RwLock<Option<Arc<dyn TerminalView>>>>,
|
proj_helper: Option<ProjectionHelper<Self>>,
|
||||||
_src_obs: Arc<RwLock<ProjectionArg<dyn TerminalView, Self>>>,
|
|
||||||
|
src: Arc<RwLock<dyn TerminalView>>,
|
||||||
level: usize,
|
level: usize,
|
||||||
|
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,24 +36,24 @@ impl LeveledTermView {
|
||||||
src_port: OuterViewPort<dyn TerminalView>,
|
src_port: OuterViewPort<dyn TerminalView>,
|
||||||
dst_port: InnerViewPort<dyn TerminalView>
|
dst_port: InnerViewPort<dyn TerminalView>
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let src_obs = ProjectionArg::new(
|
|
||||||
// we simply forward all messages
|
|
||||||
|s: Arc<RwLock<Self>>, msg: &Point2<i16>| {
|
|
||||||
s.read().unwrap().cast.notify(msg);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let v = Arc::new(RwLock::new(
|
let v = Arc::new(RwLock::new(
|
||||||
LeveledTermView {
|
LeveledTermView {
|
||||||
src: src_obs.read().unwrap().src.clone(),
|
proj_helper: None,
|
||||||
_src_obs: src_obs.clone(),
|
src: Arc::new(RwLock::new(Option::<Arc<dyn TerminalView>>::None)),
|
||||||
level: 0,
|
level: 0,
|
||||||
cast: dst_port.get_broadcast()
|
cast: dst_port.get_broadcast()
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
src_obs.write().unwrap().proj = Arc::downgrade(&v);
|
let mut projection_helper = ProjectionHelper::new(Arc::downgrade(&v));
|
||||||
|
|
||||||
|
let (src, src_obs) = projection_helper.new_arg(
|
||||||
|
|p: Arc<RwLock<Self>>, pos: &Point2<i16>| {
|
||||||
|
p.read().unwrap().cast.notify(pos);
|
||||||
|
});
|
||||||
|
|
||||||
|
v.write().unwrap().proj_helper = Some(projection_helper);
|
||||||
|
v.write().unwrap().src = src;
|
||||||
src_port.add_observer(src_obs);
|
src_port.add_observer(src_obs);
|
||||||
dst_port.set_view(Some(v.clone()));
|
dst_port.set_view(Some(v.clone()));
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
std::{
|
||||||
sync::{Arc, RwLock, Weak},
|
sync::{Arc, RwLock, Weak},
|
||||||
cmp::{max}
|
cmp::{max},
|
||||||
|
any::Any
|
||||||
},
|
},
|
||||||
|
async_std::stream::StreamExt,
|
||||||
crate::{
|
crate::{
|
||||||
core::{View, Observer, ObserverExt},
|
core::{View, Observer, ObserverExt, channel::{channel, ChannelData, ChannelSender, ChannelReceiver}},
|
||||||
singleton::{SingletonView},
|
singleton::{SingletonView},
|
||||||
sequence::{SequenceView},
|
sequence::{SequenceView},
|
||||||
index::{IndexView}
|
index::{IndexView}
|
||||||
|
@ -13,46 +15,84 @@ use {
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
/// Special Observer which can access the state of the projection on notify
|
pub struct ProjectionHelper<P: Send + Sync + 'static> {
|
||||||
/// also handles the reset() and default behaviour of unitinitalized inputs
|
keepalive: Vec<Arc<dyn Any + Send + Sync>>,
|
||||||
pub struct ProjectionArg<V, P>
|
proj: Weak<RwLock<P>>
|
||||||
where V: View + ?Sized,
|
|
||||||
P: Send + Sync {
|
|
||||||
pub src: Arc<RwLock<Option<Arc<V>>>>,
|
|
||||||
pub proj: Weak<RwLock<P>>,
|
|
||||||
notify_fn: Box<dyn Fn(Arc<RwLock<P>>, &V::Msg) + Send + Sync>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, P> ProjectionArg<V, P>
|
impl<P: Send + Sync + 'static> ProjectionHelper<P> {
|
||||||
where V: View + ?Sized,
|
pub fn new(proj: Weak<RwLock<P>>) -> Self {
|
||||||
P: Send + Sync {
|
ProjectionHelper {
|
||||||
pub fn new(f: impl Fn(Arc<RwLock<P>>, &V::Msg) + Send + Sync + 'static) -> Arc<RwLock<Self>> {
|
keepalive: Vec::new(),
|
||||||
Arc::new(RwLock::new(ProjectionArg {
|
proj
|
||||||
src: Arc::new(RwLock::new(None)),
|
|
||||||
proj: Weak::new(),
|
|
||||||
notify_fn: Box::new(f)
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_arg<
|
||||||
|
V: View + ?Sized + 'static
|
||||||
|
>(
|
||||||
|
&mut self,
|
||||||
|
notify: impl Fn(Arc<RwLock<P>>, &V::Msg) + Send + Sync + 'static
|
||||||
|
) -> (
|
||||||
|
Arc<RwLock<Option<Arc<V>>>>,
|
||||||
|
Arc<RwLock<ProjectionArg<V, Vec<V::Msg>>>>
|
||||||
|
) where V::Msg: Send + Sync {
|
||||||
|
let (tx, mut rx) = channel::<Vec<V::Msg>>();
|
||||||
|
|
||||||
|
let view = Arc::new(RwLock::new(None));
|
||||||
|
let arg = Arc::new(RwLock::new(
|
||||||
|
ProjectionArg {
|
||||||
|
src: view.clone(),
|
||||||
|
sender: tx
|
||||||
|
}));
|
||||||
|
|
||||||
|
let proj = self.proj.clone();
|
||||||
|
async_std::task::spawn(async move {
|
||||||
|
while let Some(msg) = rx.next().await {
|
||||||
|
let proj = proj.upgrade().unwrap();
|
||||||
|
notify(proj, &msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.keepalive.push(arg.clone());
|
||||||
|
|
||||||
|
(view, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Special Observer which can access the state of the projection on notify
|
||||||
|
/// also handles the reset() and default behaviour of unitinitalized inputs
|
||||||
|
pub struct ProjectionArg<V, D>
|
||||||
|
where V: View + ?Sized,
|
||||||
|
D: ChannelData<Item = V::Msg>,
|
||||||
|
D::IntoIter: Send + Sync
|
||||||
|
{
|
||||||
|
src: Arc<RwLock<Option<Arc<V>>>>,
|
||||||
|
sender: ChannelSender<D>
|
||||||
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Item, P> Observer<dyn SingletonView<Item = Item>> for ProjectionArg<dyn SingletonView<Item = Item>, P>
|
impl<Item, D> Observer<dyn SingletonView<Item = Item>> for ProjectionArg<dyn SingletonView<Item = Item>, D>
|
||||||
where P: Send + Sync {
|
where D: ChannelData<Item = ()>,
|
||||||
|
D::IntoIter: Send + Sync
|
||||||
|
{
|
||||||
fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) {
|
fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) {
|
||||||
*self.src.write().unwrap() = new_src;
|
*self.src.write().unwrap() = new_src;
|
||||||
self.notify(&());
|
self.notify(&());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&self, msg: &()) {
|
fn notify(&self, msg: &()) {
|
||||||
(self.notify_fn)(self.proj.upgrade().unwrap(), msg);
|
self.sender.send(*msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Item, P> Observer<dyn SequenceView<Item = Item>> for ProjectionArg<dyn SequenceView<Item = Item>, P>
|
impl<Item, D> Observer<dyn SequenceView<Item = Item>> for ProjectionArg<dyn SequenceView<Item = Item>, D>
|
||||||
where P: Send + Sync {
|
where D: ChannelData<Item = usize>,
|
||||||
|
D::IntoIter: Send + Sync
|
||||||
|
{
|
||||||
fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) {
|
fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) {
|
||||||
let old_len = self.src.len().unwrap_or(0);
|
let old_len = self.src.len().unwrap_or(0);
|
||||||
*self.src.write().unwrap() = new_src;
|
*self.src.write().unwrap() = new_src;
|
||||||
|
@ -62,14 +102,16 @@ where P: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&self, msg: &usize) {
|
fn notify(&self, msg: &usize) {
|
||||||
(self.notify_fn)(self.proj.upgrade().unwrap(), msg);
|
self.sender.send(*msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Key, Item, P> Observer<dyn IndexView<Key, Item = Item>> for ProjectionArg<dyn IndexView<Key, Item = Item>, P>
|
impl<Key: Clone, Item, D> Observer<dyn IndexView<Key, Item = Item>> for ProjectionArg<dyn IndexView<Key, Item = Item>, D>
|
||||||
where P: Send + Sync {
|
where D: ChannelData<Item = Key>,
|
||||||
|
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.write().unwrap() = new_src;
|
*self.src.write().unwrap() = new_src;
|
||||||
|
@ -80,7 +122,7 @@ where P: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&self, msg: &Key) {
|
fn notify(&self, msg: &Key) {
|
||||||
(self.notify_fn)(self.proj.upgrade().unwrap(), msg);
|
self.sender.send(msg.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use {
|
use {
|
||||||
std::sync::{RwLock},
|
std::{
|
||||||
|
sync::{RwLock}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort},
|
core::{ViewPort, OuterViewPort},
|
||||||
singleton::{SingletonView, SingletonBuffer},
|
singleton::{SingletonView, SingletonBuffer},
|
||||||
|
@ -97,22 +99,27 @@ impl StringEditor {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub mod insert_view {
|
pub mod insert_view {
|
||||||
use cgmath::Point2;
|
use {
|
||||||
use std::sync::{Arc, RwLock};
|
std::{
|
||||||
use std::cmp::{min, max};
|
sync::{Arc, RwLock},
|
||||||
use crate::{
|
cmp::{min, max},
|
||||||
|
any::Any,
|
||||||
|
collections::HashSet
|
||||||
|
},
|
||||||
|
cgmath::Point2,
|
||||||
|
crate::{
|
||||||
core::{View, Observer, ObserverExt, ObserverBroadcast, OuterViewPort, InnerViewPort},
|
core::{View, Observer, ObserverExt, ObserverBroadcast, OuterViewPort, InnerViewPort},
|
||||||
terminal::{TerminalAtom, TerminalStyle, TerminalView},
|
terminal::{TerminalAtom, TerminalStyle, TerminalView},
|
||||||
grid::{GridWindowIterator},
|
grid::{GridWindowIterator},
|
||||||
singleton::{SingletonView},
|
singleton::{SingletonView},
|
||||||
sequence::{SequenceView},
|
sequence::{SequenceView},
|
||||||
index::{IndexView},
|
index::{IndexView},
|
||||||
projection::ProjectionArg,
|
projection::{ProjectionHelper, ProjectionArg},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct StringInsertView {
|
pub struct StringInsertView {
|
||||||
_cursor_obs: Arc<RwLock<ProjectionArg<dyn SingletonView<Item = usize>, Self>>>,
|
proj_helper: Option<ProjectionHelper<Self>>,
|
||||||
_data_obs: Arc<RwLock<ProjectionArg<dyn SequenceView<Item = char>, Self>>>,
|
|
||||||
|
|
||||||
cursor: Arc<dyn SingletonView<Item = usize>>,
|
cursor: Arc<dyn SingletonView<Item = usize>>,
|
||||||
data: Arc<RwLock<dyn SequenceView<Item = char>>>,
|
data: Arc<RwLock<dyn SequenceView<Item = char>>>,
|
||||||
|
@ -162,7 +169,19 @@ pub mod insert_view {
|
||||||
data_port: OuterViewPort<dyn SequenceView<Item = char>>,
|
data_port: OuterViewPort<dyn SequenceView<Item = char>>,
|
||||||
out_port: InnerViewPort<dyn TerminalView>
|
out_port: InnerViewPort<dyn TerminalView>
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let cursor_obs = ProjectionArg::new(
|
let proj = Arc::new(RwLock::new(
|
||||||
|
StringInsertView {
|
||||||
|
proj_helper: None,
|
||||||
|
cursor: Arc::new(Option::<Arc<dyn SingletonView<Item = usize>>>::None),
|
||||||
|
data: Arc::new(RwLock::new(Option::<Arc<dyn SequenceView<Item = char>>>::None)),
|
||||||
|
cur_pos: 0,
|
||||||
|
cast: out_port.get_broadcast()
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut projection_helper = ProjectionHelper::new(Arc::downgrade(&proj));
|
||||||
|
|
||||||
|
let (cursor, cursor_obs) = projection_helper.new_arg(
|
||||||
|s: Arc<RwLock<Self>>, _msg| {
|
|s: Arc<RwLock<Self>>, _msg| {
|
||||||
let old_pos = s.read().unwrap().cur_pos;
|
let old_pos = s.read().unwrap().cur_pos;
|
||||||
let new_pos = s.read().unwrap().cursor.get();
|
let new_pos = s.read().unwrap().cursor.get();
|
||||||
|
@ -170,7 +189,7 @@ pub mod insert_view {
|
||||||
s.read().unwrap().cast.notify_each(GridWindowIterator::from(Point2::new(min(old_pos, new_pos) as i16,0) ..= Point2::new(max(old_pos, new_pos) as i16, 0)))
|
s.read().unwrap().cast.notify_each(GridWindowIterator::from(Point2::new(min(old_pos, new_pos) as i16,0) ..= Point2::new(max(old_pos, new_pos) as i16, 0)))
|
||||||
});
|
});
|
||||||
|
|
||||||
let data_obs = ProjectionArg::new(
|
let (data, data_obs) = projection_helper.new_arg(
|
||||||
|s: Arc<RwLock<Self>>, idx| {
|
|s: Arc<RwLock<Self>>, idx| {
|
||||||
s.read().unwrap().cast.notify(&Point2::new(
|
s.read().unwrap().cast.notify(&Point2::new(
|
||||||
if *idx < s.read().unwrap().cur_pos {
|
if *idx < s.read().unwrap().cur_pos {
|
||||||
|
@ -182,20 +201,9 @@ pub mod insert_view {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
let proj = Arc::new(RwLock::new(
|
proj.write().unwrap().proj_helper = Some(projection_helper);
|
||||||
StringInsertView {
|
proj.write().unwrap().cursor = cursor;
|
||||||
_cursor_obs: cursor_obs.clone(),
|
proj.write().unwrap().data = data;
|
||||||
_data_obs: data_obs.clone(),
|
|
||||||
|
|
||||||
cursor: cursor_obs.read().unwrap().src.clone(),
|
|
||||||
data: data_obs.read().unwrap().src.clone(),
|
|
||||||
cur_pos: 0,
|
|
||||||
cast: out_port.get_broadcast()
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
cursor_obs.write().unwrap().proj = Arc::downgrade(&proj);
|
|
||||||
data_obs.write().unwrap().proj = Arc::downgrade(&proj);
|
|
||||||
|
|
||||||
cursor_port.add_observer(cursor_obs);
|
cursor_port.add_observer(cursor_obs);
|
||||||
data_port.add_observer(data_obs);
|
data_port.add_observer(data_obs);
|
||||||
|
|
Loading…
Reference in a new issue