mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
wrapper impls for Render and Handle
This commit is contained in:
parent
3a7aa9e9a3
commit
777904cb35
4 changed files with 118 additions and 120 deletions
|
|
@ -28,7 +28,7 @@ pub fn input_thread (
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for things that handle input events.
|
/// Trait for things that handle input events.
|
||||||
pub trait Handle {
|
pub trait Handle: Send + Sync {
|
||||||
/// Handle an input event.
|
/// Handle an input event.
|
||||||
/// Returns Ok(true) if the device handled the event.
|
/// Returns Ok(true) if the device handled the event.
|
||||||
/// This is the mechanism which allows nesting of components;.
|
/// This is the mechanism which allows nesting of components;.
|
||||||
|
|
@ -37,6 +37,45 @@ pub trait Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Handle> Handle for &mut T {
|
||||||
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
|
(*self).handle(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Handle> Handle for Option<T> {
|
||||||
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
|
match self {
|
||||||
|
Some(handle) => handle.handle(e),
|
||||||
|
None => Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Handle> Handle for Mutex<T> {
|
||||||
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
|
self.lock().unwrap().handle(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Handle> Handle for Arc<Mutex<T>> {
|
||||||
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
|
self.lock().unwrap().handle(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Handle> Handle for RwLock<T> {
|
||||||
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
|
self.write().unwrap().handle(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Handle> Handle for Arc<RwLock<T>> {
|
||||||
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
|
self.write().unwrap().handle(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement the `Handle` trait.
|
/// Implement the `Handle` trait.
|
||||||
#[macro_export] macro_rules! handle {
|
#[macro_export] macro_rules! handle {
|
||||||
($T:ty) => {
|
($T:ty) => {
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// A collection of [Focusable] items.
|
|
||||||
pub struct Focus {
|
|
||||||
index: usize,
|
|
||||||
items: Vec<Focusable>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Focus {
|
|
||||||
pub fn new (items: Vec<Focusable>) -> Self {
|
|
||||||
Self {
|
|
||||||
index: 0,
|
|
||||||
items
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn item_mut (&mut self) -> &mut impl Handle {
|
|
||||||
&mut self.items[self.index]
|
|
||||||
}
|
|
||||||
/// Select next item.
|
|
||||||
pub fn next (&mut self) -> Usually<bool> {
|
|
||||||
self.index = (self.index + 1) % self.items.len();
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
/// Select previous item.
|
|
||||||
pub fn prev (&mut self) -> Usually<bool> {
|
|
||||||
self.index = match self.index {
|
|
||||||
0 => self.items.len().saturating_sub(1),
|
|
||||||
_ => self.index - 1
|
|
||||||
};
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handle!(Focus |self, e| Ok(
|
|
||||||
handle_keymap(self, e, KEYMAP_FOCUS)? || self.item_mut().handle(e)?
|
|
||||||
));
|
|
||||||
|
|
||||||
pub const KEYMAP_FOCUS: &'static [KeyBinding<Focus>] = keymap!(Focus {
|
|
||||||
[Tab, NONE, "focus_next", "focus next item", Focus::next],
|
|
||||||
[Tab, SHIFT, "focus_prev", "focus previous item", Focus::prev],
|
|
||||||
});
|
|
||||||
|
|
||||||
/// A wrapper around items that can be focused.
|
|
||||||
pub enum Focusable {
|
|
||||||
/// A monolithic focus item.
|
|
||||||
Mono(Arc<dyn Handle + Send + Sync>),
|
|
||||||
/// A focus item that contains other focus items.
|
|
||||||
Poly(Box<Focusable>),
|
|
||||||
}
|
|
||||||
|
|
||||||
handle!(Focusable |self, e| { todo!("{e:?}"); Ok(false) });
|
|
||||||
|
|
@ -46,7 +46,6 @@ use crossterm::terminal::{
|
||||||
submod! {
|
submod! {
|
||||||
exit
|
exit
|
||||||
handle
|
handle
|
||||||
handle_focus
|
|
||||||
handle_keymap
|
handle_keymap
|
||||||
jack_core
|
jack_core
|
||||||
jack_device
|
jack_device
|
||||||
|
|
|
||||||
|
|
@ -9,59 +9,76 @@ pub fn main () -> Usually<()> {
|
||||||
|
|
||||||
struct ArrangerStandalone {
|
struct ArrangerStandalone {
|
||||||
/// Contains all the sequencers.
|
/// Contains all the sequencers.
|
||||||
arranger: Arc<Arranger>,
|
arranger: Arranger,
|
||||||
/// Controls the JACK transport.
|
/// Controls the JACK transport.
|
||||||
transport: Option<Arc<RwLock<TransportToolbar>>>,
|
transport: Option<TransportToolbar>,
|
||||||
/// This allows the sequencer view to be moved or hidden.
|
/// This allows the sequencer view to be moved or hidden.
|
||||||
show_sequencer: Option<tek_core::Direction>,
|
show_sequencer: Option<tek_core::Direction>,
|
||||||
/// Proxies input events to the currently active sequencer.
|
|
||||||
sequencer_proxy: SequencerProxy,
|
|
||||||
///
|
///
|
||||||
focus_order: Vec<FocusItem>,
|
focus: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SequencerProxy;
|
impl ArrangerStandalone {
|
||||||
|
fn focus_prev (&mut self) {
|
||||||
impl Focus for SequencerProxy {}
|
self.focus = if self.focus > 0 { 1 } else { self.focus - 1 };
|
||||||
|
}
|
||||||
|
fn focus_next (&mut self) {
|
||||||
|
self.focus = if self.focus < 2 { self.focus + 1 } else { 0 };
|
||||||
|
}
|
||||||
|
fn focused (&self) -> &dyn Render {
|
||||||
|
self.focusable()[self.focus]
|
||||||
|
}
|
||||||
|
fn focusable (&self) -> [&dyn Render;2] {
|
||||||
|
[
|
||||||
|
&self.transport as &dyn Render,
|
||||||
|
&self.arranger as &dyn Render,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
fn focused_mut (&mut self) -> &mut dyn Handle {
|
||||||
|
let focus = self.focus;
|
||||||
|
self.focusable_mut()[focus]
|
||||||
|
}
|
||||||
|
fn focusable_mut (&mut self) -> [&mut dyn Handle;2] {
|
||||||
|
[
|
||||||
|
&mut self.transport as &mut dyn Handle,
|
||||||
|
&mut self.arranger as &mut dyn Handle
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct ArrangerCli {
|
pub struct ArrangerCli {
|
||||||
/// Name of JACK client
|
/// Name of JACK client
|
||||||
#[arg(short, long)] name: Option<String>,
|
#[arg(short, long)]
|
||||||
|
name: Option<String>,
|
||||||
/// Pulses per quarter note (arruencer resolution; default: 96)
|
/// Pulses per quarter note (arruencer resolution; default: 96)
|
||||||
#[arg(short, long)] ppq: Option<usize>,
|
#[arg(short, long)]
|
||||||
|
ppq: Option<usize>,
|
||||||
/// Whether to include a transport toolbar (default: true)
|
/// Whether to include a transport toolbar (default: true)
|
||||||
#[arg(short, long)] transport: Option<bool>,
|
#[arg(short, long)]
|
||||||
|
transport: Option<bool>,
|
||||||
/// Number of tracks
|
/// Number of tracks
|
||||||
#[arg(short = 'x', long, default_value_t = 8)] tracks: usize,
|
#[arg(short = 'x', long, default_value_t = 8)]
|
||||||
|
tracks: usize,
|
||||||
/// Number of scenes
|
/// Number of scenes
|
||||||
#[arg(short, long, default_value_t = 8)] scenes: usize,
|
#[arg(short, long, default_value_t = 8)]
|
||||||
|
scenes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ArrangerStandalone<'a> {
|
impl ArrangerStandalone {
|
||||||
pub fn from_args () -> Usually<Self> {
|
pub fn from_args () -> Usually<Self> {
|
||||||
let args = ArrangerCli::parse();
|
let args = ArrangerCli::parse();
|
||||||
let arranger = Arranger::new("");
|
let mut arranger = Arranger::new("");
|
||||||
let transport = match args.transport {
|
let transport = match args.transport {
|
||||||
Some(true) => Some(Arc::new(RwLock::new(TransportToolbar::new(None)))),
|
Some(true) => Some(TransportToolbar::new(None)),
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
let sequencer_proxy = SequencerProxy;
|
|
||||||
let mut app = ArrangerStandalone {
|
|
||||||
transport,
|
|
||||||
show_sequencer: Some(tek_core::Direction::Down),
|
|
||||||
arranger,
|
|
||||||
sequencer_proxy,
|
|
||||||
focus_order: vec![],
|
|
||||||
};
|
|
||||||
app.focus_order.push(FocusItem::Mono(&app.arranger));
|
|
||||||
app.focus_order.push(FocusItem::Poly(&app.sequencer_proxy));
|
|
||||||
if let Some(name) = args.name {
|
if let Some(name) = args.name {
|
||||||
*app.arranger.name.write().unwrap() = name.clone();
|
*arranger.name.write().unwrap() = name.clone();
|
||||||
}
|
}
|
||||||
for _ in 0..args.tracks {
|
for _ in 0..args.tracks {
|
||||||
let track = app.arranger.track_add(None)?;
|
let track = arranger.track_add(None)?;
|
||||||
for _ in 0..args.scenes {
|
for _ in 0..args.scenes {
|
||||||
track.phrases.push(
|
track.phrases.push(
|
||||||
Arc::new(RwLock::new(Phrase::new("", 96 * 4, None)))
|
Arc::new(RwLock::new(Phrase::new("", 96 * 4, None)))
|
||||||
|
|
@ -69,30 +86,28 @@ impl<'a> ArrangerStandalone<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _ in 0..args.scenes {
|
for _ in 0..args.scenes {
|
||||||
let scene = app.arranger.scene_add(None)?;
|
let _scene = arranger.scene_add(None)?;
|
||||||
//for i in 0..args.tracks {
|
//for i in 0..args.tracks {
|
||||||
//scene.clips[i] = Some(i);
|
//scene.clips[i] = Some(i);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
Ok(app)
|
Ok(ArrangerStandalone {
|
||||||
|
transport,
|
||||||
|
show_sequencer: Some(tek_core::Direction::Down),
|
||||||
|
arranger,
|
||||||
|
focus: 0
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for ArrangerStandalone {
|
impl Render for ArrangerStandalone {
|
||||||
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
||||||
let mut layout = Split::down();
|
|
||||||
if let Some(transport) = &self.transport {
|
|
||||||
layout = layout.add_ref(transport);
|
|
||||||
}
|
|
||||||
let sequencer = self.arranger.sequencer();
|
let sequencer = self.arranger.sequencer();
|
||||||
if let Some(direction) = self.show_sequencer {
|
let result = Split::down()
|
||||||
layout = layout.add(Split::new(direction)
|
.add_ref(&self.transport)
|
||||||
.add_ref(&self.arranger)
|
.add_ref(&self.arranger)
|
||||||
.add(sequencer))
|
.add_ref(&sequencer)
|
||||||
} else {
|
.render(buf, area)?;
|
||||||
layout = layout.add_ref(&self.arranger)
|
|
||||||
}
|
|
||||||
let result = layout.render(buf, area)?;
|
|
||||||
if let Some(ref modal) = self.arranger.modal {
|
if let Some(ref modal) = self.arranger.modal {
|
||||||
fill_bg(buf, area, Nord::bg_lo(false, false));
|
fill_bg(buf, area, Nord::bg_lo(false, false));
|
||||||
fill_fg(buf, area, Nord::bg_hi(false, false));
|
fill_fg(buf, area, Nord::bg_hi(false, false));
|
||||||
|
|
@ -104,31 +119,27 @@ impl Render for ArrangerStandalone {
|
||||||
|
|
||||||
impl Handle for ArrangerStandalone {
|
impl Handle for ArrangerStandalone {
|
||||||
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
if let Some(modal) = self.arranger.modal.as_mut() {
|
match e {
|
||||||
let result = modal.handle(e)?;
|
AppEvent::Input(Event::Key(KeyEvent { code: KeyCode::Tab, .. })) => {
|
||||||
if modal.exited() {
|
self.focus_next();
|
||||||
self.arranger.modal = None;
|
Ok(true)
|
||||||
}
|
},
|
||||||
Ok(result)
|
AppEvent::Input(Event::Key(KeyEvent { code: KeyCode::BackTab, .. })) => {
|
||||||
} else {
|
self.focus_prev();
|
||||||
match e {
|
Ok(true)
|
||||||
AppEvent::Input(Event::Key(k)) => {
|
},
|
||||||
Ok(false)
|
_ => self.focused_mut().handle(e)
|
||||||
//if k.code == KeyCode::Tab {
|
}
|
||||||
//self.arranger.focus_sequencer = !self.arranger.focus_sequencer;
|
}
|
||||||
//Ok(true)
|
}
|
||||||
//} else if self.arranger.focus_sequencer {
|
|
||||||
//if let Some(sequencer) = self.arranger.sequencer_mut() {
|
struct SequencerProxy(Arc<RwLock<Arranger>>);
|
||||||
//handle_keymap(sequencer, e, KEYMAP_SEQUENCER)
|
|
||||||
//} else {
|
impl Handle for SequencerProxy {
|
||||||
//Ok(false)
|
fn handle (&mut self, e: &AppEvent) -> Usually<bool> {
|
||||||
//}
|
match self.0.write().unwrap().sequencer_mut() {
|
||||||
//} else {
|
Some(sequencer) => sequencer.handle(e),
|
||||||
//handle_keymap(&mut self.arranger, e, KEYMAP_ARRANGER)
|
None => Ok(false)
|
||||||
//}
|
|
||||||
},
|
|
||||||
_ => Ok(false),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue