add TerminalCompositor
and some nice utilities for ports
This commit is contained in:
parent
62f3a85736
commit
4a29d7a5cf
4 changed files with 143 additions and 43 deletions
114
src/main.rs
114
src/main.rs
|
@ -19,53 +19,83 @@ use {
|
|||
cgmath::{Vector2},
|
||||
crate::{
|
||||
view::{View, Observer},
|
||||
port::{InnerViewPort, OuterViewPort},
|
||||
port::{ViewPort, InnerViewPort, OuterViewPort},
|
||||
singleton_buffer::SingletonBuffer,
|
||||
vec_buffer::VecBuffer,
|
||||
terminal::{Terminal, TerminalAtom, TerminalStyle}
|
||||
terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalCompositor}
|
||||
}
|
||||
};
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let digits = port::ViewPort::new();
|
||||
let mut buf = VecBuffer::new(digits.inner());
|
||||
struct Fill(TerminalAtom);
|
||||
impl View for Fill {
|
||||
type Key = Vector2<i16>;
|
||||
type Value = TerminalAtom;
|
||||
|
||||
let digit_view = digits.outer()
|
||||
// digit encoding
|
||||
.map_value(
|
||||
|digit|
|
||||
if let Some(digit) = digit {
|
||||
Some(TerminalAtom::new(char::from_digit(digit, 16).unwrap(), TerminalStyle::bg_color((100,30,30))))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
)
|
||||
// simple horizontal layout
|
||||
.map_key(
|
||||
|idx| Vector2::<i16>::new(idx as i16, 0),
|
||||
|pos| pos.x as usize
|
||||
);
|
||||
|
||||
let fut = task::spawn(Terminal::show(digit_view));
|
||||
|
||||
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||
buf.push(0);
|
||||
buf.push(10);
|
||||
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||
buf.push(2);
|
||||
buf.push(3);
|
||||
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||
buf.push(4);
|
||||
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||
buf.insert(0, 15);
|
||||
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||
buf.remove(2);
|
||||
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||
|
||||
drop(buf);
|
||||
drop(digits);
|
||||
|
||||
fut.await;
|
||||
fn view(&self, _: Vector2<i16>) -> Option<TerminalAtom> {
|
||||
Some(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let composite_view = port::ViewPort::new();
|
||||
let mut compositor = TerminalCompositor::new(composite_view.inner());
|
||||
|
||||
task::spawn(async move {
|
||||
// background
|
||||
let fp = port::ViewPort::with_view(Arc::new(Fill(TerminalAtom::new('.', TerminalStyle::fg_color((50,50,50))))));
|
||||
compositor.push(fp.outer());
|
||||
|
||||
// view of Vec<u32>
|
||||
let digits = port::ViewPort::new();
|
||||
let mut buf = VecBuffer::new(digits.inner());
|
||||
compositor.push(
|
||||
digits.outer()
|
||||
.map_value( // digit encoding
|
||||
|digit|
|
||||
if let Some(digit) = digit {
|
||||
Some(TerminalAtom::new(
|
||||
char::from_digit(digit, 16).unwrap(),
|
||||
TerminalStyle::bg_color((100,30,30)).add(
|
||||
TerminalStyle::fg_color((255,255,255)))))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
)
|
||||
.map_key( // a lightly tilted layout
|
||||
// mapping from index to position in 2D-grid
|
||||
|idx| Vector2::<i16>::new(idx as i16, idx as i16 / 2),
|
||||
// reverse mapping from position to idx
|
||||
|pos| pos.x as usize
|
||||
));
|
||||
|
||||
// TODO: use the real terminal size...
|
||||
for x in 0 .. 10 {
|
||||
for y in 0 .. 10 {
|
||||
fp.inner().notify(Vector2::new(x,y));
|
||||
}
|
||||
}
|
||||
|
||||
// now some modifications on our VecBuffer, which will automatically update the View
|
||||
buf.push(0);
|
||||
buf.push(10);
|
||||
task::sleep(std::time::Duration::from_millis(400)).await;
|
||||
buf.push(2);
|
||||
buf.push(3);
|
||||
task::sleep(std::time::Duration::from_millis(400)).await;
|
||||
buf.push(4);
|
||||
task::sleep(std::time::Duration::from_millis(400)).await;
|
||||
buf.insert(0, 15);
|
||||
task::sleep(std::time::Duration::from_millis(400)).await;
|
||||
buf.remove(2);
|
||||
task::sleep(std::time::Duration::from_millis(400)).await;
|
||||
|
||||
for x in 0 .. 4 {
|
||||
buf.remove(0);
|
||||
task::sleep(std::time::Duration::from_millis(400)).await;
|
||||
}
|
||||
});
|
||||
|
||||
Terminal::show(composite_view.into_outer()).await;
|
||||
}
|
||||
|
||||
|
|
17
src/port.rs
17
src/port.rs
|
@ -31,6 +31,13 @@ where K: Send + Sync + 'static,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn with_view(view: Arc<dyn View<Key = K, Value = V>>) -> Self {
|
||||
ViewPort {
|
||||
view: Arc::new(RwLock::new(Some(view))),
|
||||
observers: Arc::new(RwLock::new(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_view(&self, view: Arc<dyn View<Key = K, Value = V>>) {
|
||||
*self.view.write().unwrap() = Some(view);
|
||||
}
|
||||
|
@ -46,6 +53,14 @@ where K: Send + Sync + 'static,
|
|||
pub fn outer(&self) -> OuterViewPort<K, V> {
|
||||
OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> InnerViewPort<K, V> {
|
||||
InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
|
||||
}
|
||||
|
||||
pub fn into_outer(self) -> OuterViewPort<K, V> {
|
||||
OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
|
||||
}
|
||||
}
|
||||
|
||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
@ -74,7 +89,7 @@ impl<K: Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
|
|||
}
|
||||
|
||||
impl<K: Eq + Hash + Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
|
||||
pub fn stream(&self) -> ChannelReceiver<HashSet<K>> {
|
||||
pub fn stream(self) -> ChannelReceiver<HashSet<K>> {
|
||||
let (s, r) = crate::channel::set_channel();
|
||||
self.0.add_observer(Arc::new(s));
|
||||
r
|
||||
|
|
53
src/terminal/compositor.rs
Normal file
53
src/terminal/compositor.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use {
|
||||
std::sync::{Arc, RwLock},
|
||||
cgmath::Vector2,
|
||||
crate::{
|
||||
view::{View, Observer},
|
||||
port::{ViewPort, InnerViewPort, OuterViewPort},
|
||||
terminal::{TerminalAtom}
|
||||
}
|
||||
};
|
||||
|
||||
pub struct TerminalCompositor {
|
||||
layers: Arc<RwLock<Vec<Arc<dyn View<Key = Vector2<i16>, Value = TerminalAtom>>>>>,
|
||||
port: Arc<InnerViewPort<Vector2<i16>, TerminalAtom>>
|
||||
}
|
||||
|
||||
impl TerminalCompositor {
|
||||
pub fn new(port: InnerViewPort<Vector2<i16>, TerminalAtom>) -> Self {
|
||||
let layers = Arc::new(RwLock::new(Vec::<Arc<dyn View<Key = Vector2<i16>, Value = TerminalAtom>>>::new()));
|
||||
|
||||
port.set_view_fn({
|
||||
let layers = layers.clone();
|
||||
move |pos| {
|
||||
let mut atom = None;
|
||||
|
||||
for l in layers.read().unwrap().iter() {
|
||||
match (atom, l.view(pos)) {
|
||||
(None, next) => atom = next,
|
||||
(Some(last), Some(next)) => atom = Some(next.add_style_back(last.style)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
atom
|
||||
}
|
||||
});
|
||||
|
||||
TerminalCompositor {
|
||||
layers,
|
||||
port: Arc::new(port)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, v: OuterViewPort<Vector2<i16>, TerminalAtom>) {
|
||||
self.layers.write().unwrap().push(v.add_observer(self.port.clone()));
|
||||
}
|
||||
|
||||
pub fn make_port(&mut self) -> InnerViewPort<Vector2<i16>, TerminalAtom> {
|
||||
let port = ViewPort::new();
|
||||
self.push(port.outer());
|
||||
port.inner()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
pub mod style;
|
||||
pub mod atom;
|
||||
pub mod terminal;
|
||||
pub mod compositor;
|
||||
|
||||
pub use {
|
||||
style::{TerminalStyle},
|
||||
atom::{TerminalAtom},
|
||||
terminal::{Terminal, TerminalEvent},
|
||||
compositor::TerminalCompositor
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue