This commit is contained in:
🪞👃🪞 2024-07-03 00:08:41 +03:00
parent 3ae2467acc
commit 94c1f83ef2
13 changed files with 277 additions and 124 deletions

View file

@ -16,7 +16,7 @@ pub struct DynamicDevice<T> {
pub render: Mutex<Box<dyn FnMut(&T, &mut Buffer, Rect)->Usually<Rect> + Send>>,
pub handle: Arc<Mutex<Box<dyn FnMut(&mut T, &AppEvent)->Usually<bool> + Send>>>,
pub process: Arc<Mutex<Box<dyn FnMut(&mut T, &Client, &ProcessScope)->Control + Send>>>,
pub client: Option<DynamicAsyncClient>
pub client: Option<DynamicAsyncClient>
}
impl<T> Handle for DynamicDevice<T> {
@ -46,10 +46,6 @@ impl<T: PortList + Send + Sync + 'static> PortList for DynamicDevice<T> {
}
}
type DynamicAsyncClient = AsyncClient<DynamicNotifications, DynamicProcessHandler>;
type DynamicNotifications = Notifications<Box<dyn Fn(AppEvent) + Send + Sync>>;
type DynamicProcessHandler = ClosureProcessHandler<BoxedProcessHandler>;
impl<T: Send + Sync + 'static> DynamicDevice<T> {
pub fn new <'a, R, H, P> (render: R, handle: H, process: P, state: T) -> Self where
R: FnMut(&T, &mut Buffer, Rect) -> Usually<Rect> + Send + 'static,

View file

@ -1,13 +1,37 @@
use crate::core::*;
pub type BoxedNotificationHandler =
Box<dyn Fn(AppEvent) + Send>;
pub trait Process {
fn process (&mut self, c: &Client, s: &ProcessScope) -> Control;
}
pub type DynamicAsyncClient =
AsyncClient<DynamicNotifications, DynamicProcessHandler>;
pub type DynamicNotifications =
Notifications<Box<dyn Fn(AppEvent) + Send + Sync>>;
pub type DynamicProcessHandler =
ClosureProcessHandler<BoxedProcessHandler>;
pub type BoxedProcessHandler =
Box<dyn FnMut(&Client, &ProcessScope)-> Control + Send>;
pub type Jack<N> =
AsyncClient<N, ClosureProcessHandler<BoxedProcessHandler>>;
pub fn jack_run <T> (name: &str, app: &Arc<Mutex<T>>) -> Usually<DynamicAsyncClient>
where T: Handle + Process + Send + 'static
{
let options = ClientOptions::NO_START_SERVER;
let (client, _status) = Client::new(name, options)?;
Ok(client.activate_async(
Notifications(Box::new({
let app = app.clone();
move|event|{app.lock().unwrap().handle(&event).unwrap();}
}) as Box<dyn Fn(AppEvent) + Send + Sync>),
ClosureProcessHandler::new(Box::new({
let app = app.clone();
move|c: &Client, s: &ProcessScope|{app.lock().unwrap().process(c, s)}
}) as BoxedProcessHandler)
)?)
}
pub use ::jack::{
AsyncClient,

View file

@ -1,33 +1,20 @@
pub type Usually<T> = Result<T, Box<dyn Error>>;
macro_rules! submod {
($($name:ident)*) => { $(mod $name; pub use self::$name::*;)* };
}
submod!( device handle jack keymap port render run time );
pub use std::error::Error;
pub use std::io::{stdout, Stdout, Write};
pub use std::thread::{spawn, JoinHandle};
pub use std::time::Duration;
pub use std::collections::BTreeMap;
pub use std::sync::{
Arc, Mutex, MutexGuard,
atomic::{Ordering, AtomicBool, AtomicUsize},
mpsc::{self, channel, Sender, Receiver}
};
pub use std::sync::{Arc, Mutex, MutexGuard};
pub use std::sync::atomic::{Ordering, AtomicBool, AtomicUsize};
pub use std::sync::mpsc::{channel, Sender, Receiver};
pub use ratatui::prelude::*;
pub use midly::{MidiMessage, live::LiveEvent, num::u7};
pub use crossterm::{ExecutableCommand, QueueableCommand};
pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
pub use ::crossterm::{
ExecutableCommand, QueueableCommand,
event::{Event, KeyEvent, KeyCode, KeyModifiers},
terminal::{
self,
Clear, ClearType,
EnterAlternateScreen, LeaveAlternateScreen,
enable_raw_mode, disable_raw_mode
},
};
macro_rules! submod { ($($name:ident)*) => { $(mod $name; pub use self::$name::*;)* }; }
submod!( device handle jack keymap port render run time );
pub type Usually<T> = Result<T, Box<dyn Error>>;
pub use ::ratatui::prelude::*;
pub use ::midly::{MidiMessage, live::LiveEvent, num::u7};
pub use crate::{key, keymap};

View file

@ -21,6 +21,16 @@ pub trait Render {
fn max_height (&self) -> u16 {
u16::MAX
}
//fn boxed (self) -> Box<dyn Render> where Self: Sized + 'static {
//Box::new(self)
//}
}
impl<T: Fn(&mut Buffer, Rect) -> Usually<Rect>> Render for T {
fn render (&self, b: &mut Buffer, a: Rect) -> Usually<Rect> {
(*self).render(b, a)
}
}
impl Render for Box<dyn Device> {

View file

@ -1,13 +1,21 @@
use crate::core::*;
use crossterm::terminal::{
EnterAlternateScreen, LeaveAlternateScreen,
enable_raw_mode, disable_raw_mode
};
pub trait Run: Render + Handle + Send + Sized + 'static {
fn run (self) -> Usually<()> {
fn run (self, callback: Option<impl FnOnce(Arc<Mutex<Self>>)->Usually<()>>) -> Usually<()> {
let device = Arc::new(Mutex::new(self));
let exited = Arc::new(AtomicBool::new(false));
let _input_thread = input_thread(&exited, &device);
terminal_setup()?;
panic_hook_setup();
main_thread(&exited, &device)?;
let main_thread = main_thread(&exited, &device)?;
if let Some(callback) = callback {
callback(device);
}
main_thread.join();
terminal_teardown()?;
Ok(())
}
@ -67,12 +75,13 @@ pub fn panic_hook_setup () {
/// Main thread render loop
pub fn main_thread (
exited: &Arc<AtomicBool>,
device: &Arc<Mutex<impl Render>>
) -> Usually<()> {
device: &Arc<Mutex<impl Render + Send + 'static>>
) -> Usually<JoinHandle<()>> {
let exited = exited.clone();
let device = device.clone();
let mut terminal = ratatui::Terminal::new(CrosstermBackend::new(stdout()))?;
let sleep = std::time::Duration::from_millis(16);
loop {
Ok(spawn(move || loop {
terminal.draw(|frame|{
let area = frame.size();
@ -86,8 +95,7 @@ pub fn main_thread (
std::thread::sleep(sleep);
}
Ok(())
}))
}
/// Cleanup
pub fn terminal_teardown () -> Usually<()> {

View file

@ -1,5 +1,6 @@
use crate::core::*;
#[derive(Default)]
pub struct Timebase {
/// Frames per second
pub rate: ::atomic_float::AtomicF64,