mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
Compare commits
4 commits
a67481ab04
...
a77536c234
| Author | SHA1 | Date | |
|---|---|---|---|
| a77536c234 | |||
| 55b6745d4d | |||
| 79bf493004 | |||
| ff2e981e18 |
10 changed files with 221 additions and 121 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -1521,6 +1521,7 @@ dependencies = [
|
||||||
"tek_device",
|
"tek_device",
|
||||||
"tek_engine",
|
"tek_engine",
|
||||||
"tengri",
|
"tengri",
|
||||||
|
"tengri_proc",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1601,6 +1602,15 @@ dependencies = [
|
||||||
"tengri_dsl",
|
"tengri_dsl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tengri_proc"
|
||||||
|
version = "0.13.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tengri_tui"
|
name = "tengri_tui"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,13 @@ lto = false
|
||||||
|
|
||||||
[workspace.dependencies.tengri]
|
[workspace.dependencies.tengri]
|
||||||
path = "./deps/tengri/tengri"
|
path = "./deps/tengri/tengri"
|
||||||
#git = "https://codeberg.org/unspeaker/tengri"
|
|
||||||
#rev = "6048d24"
|
|
||||||
features = [ "tui", "dsl" ]
|
features = [ "tui", "dsl" ]
|
||||||
|
|
||||||
|
[workspace.dependencies.tengri_proc]
|
||||||
|
path = "./deps/tengri/proc"
|
||||||
|
|
||||||
[workspace.dependencies.jack]
|
[workspace.dependencies.jack]
|
||||||
#git = "https://codeberg.org/unspeaker/rust-jack"
|
|
||||||
#rev = "a13c1c4"
|
|
||||||
path = "./deps/rust-jack"
|
path = "./deps/rust-jack"
|
||||||
#default-features = false
|
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
tek_device = { path = "./crates/device" }
|
tek_device = { path = "./crates/device" }
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
:arranger))))))
|
:arranger))))))
|
||||||
|
|
||||||
(keys
|
(keys
|
||||||
|
(layer-if :mode-device-add "./keys_device_add.edn")
|
||||||
(layer-if :mode-pool-import "./keys_pool_file.edn")
|
(layer-if :mode-pool-import "./keys_pool_file.edn")
|
||||||
(layer-if :mode-pool-export "./keys_pool_file.edn")
|
(layer-if :mode-pool-export "./keys_pool_file.edn")
|
||||||
(layer-if :mode-pool-rename "./keys_clip_rename.edn")
|
(layer-if :mode-pool-rename "./keys_clip_rename.edn")
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
(@t select :track 0)
|
|
||||||
(@tab edit :clip)
|
|
||||||
(@c color)
|
(@c color)
|
||||||
(@q launch)
|
(@q launch)
|
||||||
|
(@t select :track 0)
|
||||||
|
(@tab edit :clip)
|
||||||
(@shift-I input add)
|
(@shift-I input add)
|
||||||
(@shift-O output add)
|
(@shift-O output add)
|
||||||
(@shift-S scene add)
|
(@shift-S scene add)
|
||||||
(@shift-T track add)
|
(@shift-T track add)
|
||||||
|
(@shift-Z device picker)
|
||||||
|
|
||||||
(@up select :scene-prev)
|
(@up select :scene-prev)
|
||||||
(@w select :scene-prev)
|
(@w select :scene-prev)
|
||||||
|
|
|
||||||
4
config/keys_device_add.edn
Normal file
4
config/keys_device_add.edn
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
(@esc device select-cancel)
|
||||||
|
(@up device pick :device-kind-prev)
|
||||||
|
(@down device pick :device-kind-next)
|
||||||
|
(@enter device add :device-kind)
|
||||||
|
|
@ -5,6 +5,7 @@ version = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tengri = { workspace = true }
|
tengri = { workspace = true }
|
||||||
|
tengri_proc = { workspace = true }
|
||||||
|
|
||||||
tek_engine = { workspace = true }
|
tek_engine = { workspace = true }
|
||||||
tek_device = { workspace = true }
|
tek_device = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,20 @@ macro_rules! ns { ($C:ty, $s:expr, $a:expr, $W:expr) => { <$C>::try_from_expr($s
|
||||||
macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; }
|
macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; }
|
||||||
macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; }
|
macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; }
|
||||||
|
|
||||||
|
handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.config.keys.command(self, input) {
|
||||||
|
let undo = command.execute(self)?;
|
||||||
|
if let Some(undo) = undo {
|
||||||
|
self.history.push(undo);
|
||||||
|
}
|
||||||
|
Some(true)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}));
|
||||||
|
|
||||||
expose!([self: Tek]
|
expose!([self: Tek]
|
||||||
([bool]
|
([bool]
|
||||||
(":mode-editor" self.is_editing())
|
(":mode-editor" self.is_editing())
|
||||||
|
(":mode-device-add" matches!(self.modal, Some(Modal::Device(..))))
|
||||||
(":mode-clip" !self.is_editing() && self.selected.is_clip())
|
(":mode-clip" !self.is_editing() && self.selected.is_clip())
|
||||||
(":mode-track" !self.is_editing() && self.selected.is_track())
|
(":mode-track" !self.is_editing() && self.selected.is_track())
|
||||||
(":mode-scene" !self.is_editing() && self.selected.is_scene())
|
(":mode-scene" !self.is_editing() && self.selected.is_scene())
|
||||||
|
|
@ -35,7 +46,22 @@ expose!([self: Tek]
|
||||||
(":w-sidebar" self.w_sidebar()))
|
(":w-sidebar" self.w_sidebar()))
|
||||||
([usize]
|
([usize]
|
||||||
(":scene-last" self.scenes.len())
|
(":scene-last" self.scenes.len())
|
||||||
(":track-last" self.tracks.len()))
|
(":track-last" self.tracks.len())
|
||||||
|
(":device-kind" if let Some(Modal::Device(index)) = self.modal {
|
||||||
|
index
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
(":device-kind-prev" if let Some(Modal::Device(index)) = self.modal {
|
||||||
|
index.overflowing_sub(1).0.min(self.device_kinds().len().saturating_sub(1))
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
(":device-kind-next" if let Some(Modal::Device(index)) = self.modal {
|
||||||
|
(index + 1) % self.device_kinds().len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}))
|
||||||
([Option<usize>]
|
([Option<usize>]
|
||||||
(":scene" self.selected.scene())
|
(":scene" self.selected.scene())
|
||||||
(":track" self.selected.track()))
|
(":track" self.selected.track()))
|
||||||
|
|
@ -49,58 +75,45 @@ expose!([self: Tek]
|
||||||
(":scene-prev" self.selected.scene_prev())
|
(":scene-prev" self.selected.scene_prev())
|
||||||
(":track-next" self.selected.track_next(self.tracks.len()))
|
(":track-next" self.selected.track_next(self.tracks.len()))
|
||||||
(":track-prev" self.selected.track_prev())));
|
(":track-prev" self.selected.track_prev())));
|
||||||
provide!(bool: |self: MidiPool| {});
|
expose!([self: MidiPool]
|
||||||
provide!(MidiClip: |self: MidiPool| {
|
([bool])
|
||||||
":new-clip" => self.new_clip(),
|
([PathBuf])
|
||||||
":cloned-clip" => self.cloned_clip(),
|
([Arc<str>])
|
||||||
});
|
([MidiClip]
|
||||||
provide!(PathBuf: |self: MidiPool| {});
|
(":new-clip" self.new_clip())
|
||||||
provide!(Arc<str>: |self: MidiPool| {});
|
(":cloned-clip" self.cloned_clip()))
|
||||||
provide!(usize: |self: MidiPool| {
|
([usize]
|
||||||
":current" => 0,
|
(":current" 0)
|
||||||
":after" => 0,
|
(":after" 0)
|
||||||
":previous" => 0,
|
(":previous" 0)
|
||||||
":next" => 0
|
(":next" 0))
|
||||||
});
|
([ItemColor]
|
||||||
provide!(ItemColor: |self: MidiPool| {
|
(":random-color" ItemColor::random())));
|
||||||
":random-color" => ItemColor::random()
|
expose!([self: MidiEditor]
|
||||||
});
|
([bool]
|
||||||
provide!(bool: |self: MidiEditor| {
|
(":true" true)
|
||||||
":true" => true,
|
(":false" false)
|
||||||
":false" => false,
|
(":time-lock" self.time_lock().get())
|
||||||
":time-lock" => self.time_lock().get(),
|
(":time-lock-toggle" !self.time_lock().get()))
|
||||||
":time-lock-toggle" => !self.time_lock().get(),
|
([usize]
|
||||||
});
|
(":note-length" self.note_len())
|
||||||
provide!(usize: |self: MidiEditor| {
|
(":note-pos" self.note_pos())
|
||||||
":note-length" => self.note_len(),
|
(":note-pos-next" self.note_pos() + 1)
|
||||||
":note-pos" => self.note_pos(),
|
(":note-pos-prev" self.note_pos().saturating_sub(1))
|
||||||
":note-pos-next" => self.note_pos() + 1,
|
(":note-pos-next-octave" self.note_pos() + 12)
|
||||||
":note-pos-prev" => self.note_pos().saturating_sub(1),
|
(":note-pos-prev-octave" self.note_pos().saturating_sub(12))
|
||||||
":note-pos-next-octave" => self.note_pos() + 12,
|
(":note-len" self.note_len())
|
||||||
":note-pos-prev-octave" => self.note_pos().saturating_sub(12),
|
(":note-len-next" self.note_len() + 1)
|
||||||
":note-len" => self.note_len(),
|
(":note-len-prev" self.note_len().saturating_sub(1))
|
||||||
":note-len-next" => self.note_len() + 1,
|
(":note-range" self.note_axis().get())
|
||||||
":note-len-prev" => self.note_len().saturating_sub(1),
|
(":note-range-prev" self.note_axis().get() + 1)
|
||||||
":note-range" => self.note_axis().get(),
|
(":note-range-next" self.note_axis().get().saturating_sub(1))
|
||||||
":note-range-prev" => self.note_axis().get() + 1,
|
(":time-pos" self.time_pos())
|
||||||
":note-range-next" => self.note_axis().get().saturating_sub(1),
|
(":time-pos-next" self.time_pos() + self.time_zoom().get())
|
||||||
":time-pos" => self.time_pos(),
|
(":time-pos-prev" self.time_pos().saturating_sub(self.time_zoom().get()))
|
||||||
":time-pos-next" => self.time_pos() + self.time_zoom().get(),
|
(":time-zoom" self.time_zoom().get())
|
||||||
":time-pos-prev" => self.time_pos().saturating_sub(self.time_zoom().get()),
|
(":time-zoom-next" self.time_zoom().get() + 1)
|
||||||
":time-zoom" => self.time_zoom().get(),
|
(":time-zoom-prev" self.time_zoom().get().saturating_sub(1).max(1))));
|
||||||
":time-zoom-next" => self.time_zoom().get() + 1,
|
|
||||||
":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1),
|
|
||||||
});
|
|
||||||
|
|
||||||
handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.config.keys.command(self, input) {
|
|
||||||
let undo = command.execute(self)?;
|
|
||||||
if let Some(undo) = undo {
|
|
||||||
self.history.push(undo);
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}));
|
|
||||||
|
|
||||||
impose!([app: Tek]
|
impose!([app: Tek]
|
||||||
(TekCommand:
|
(TekCommand:
|
||||||
|
|
@ -123,6 +136,7 @@ impose!([app: Tek]
|
||||||
("input" [,..a] ns!(InputCommand, app, a, Self::Input))
|
("input" [,..a] ns!(InputCommand, app, a, Self::Input))
|
||||||
("output" [,..a] ns!(OutputCommand, app, a, Self::Output))
|
("output" [,..a] ns!(OutputCommand, app, a, Self::Output))
|
||||||
("clip" [,..a] ns!(ClipCommand, app, a, Self::Clip))
|
("clip" [,..a] ns!(ClipCommand, app, a, Self::Clip))
|
||||||
|
("device" [,..a] ns!(DeviceCommand, app, a, Self::Device))
|
||||||
("pool" [,..a] app.pool.as_ref().map(|p|ns!(PoolCommand, p, a, Self::Pool)).flatten())
|
("pool" [,..a] app.pool.as_ref().map(|p|ns!(PoolCommand, p, a, Self::Pool)).flatten())
|
||||||
("editor" [,..a] app.editor().map(|e|ns!(MidiEditCommand, e, a, Self::Editor)).flatten())
|
("editor" [,..a] app.editor().map(|e|ns!(MidiEditCommand, e, a, Self::Editor)).flatten())
|
||||||
("sampler" [,..a] app.sampler().map(|s|ns!(SamplerCommand, s, a, Self::Sampler)).flatten())
|
("sampler" [,..a] app.sampler().map(|s|ns!(SamplerCommand, s, a, Self::Sampler)).flatten())
|
||||||
|
|
@ -147,6 +161,11 @@ impose!([app: Tek]
|
||||||
(OutputCommand:
|
(OutputCommand:
|
||||||
("add" [] Some(Self::Add)))
|
("add" [] Some(Self::Add)))
|
||||||
|
|
||||||
|
(DeviceCommand:
|
||||||
|
("picker" [] Some(Self::Picker))
|
||||||
|
("pick" [index: usize] Some(Self::Pick(index.unwrap())))
|
||||||
|
("add" [index: usize] Some(Self::Add(index.unwrap()))))
|
||||||
|
|
||||||
(SceneCommand:
|
(SceneCommand:
|
||||||
("add" [] Some(Self::Add))
|
("add" [] Some(Self::Add))
|
||||||
("delete" [a: Option<usize>] Some(Self::Del(a.flatten().unwrap())))
|
("delete" [a: Option<usize>] Some(Self::Del(a.flatten().unwrap())))
|
||||||
|
|
@ -178,6 +197,7 @@ defcom!([self, app: Tek]
|
||||||
(Input [cmd: InputCommand] cmd.delegate(app, Self::Input)?)
|
(Input [cmd: InputCommand] cmd.delegate(app, Self::Input)?)
|
||||||
(Clip [cmd: ClipCommand] cmd.delegate(app, Self::Clip)?)
|
(Clip [cmd: ClipCommand] cmd.delegate(app, Self::Clip)?)
|
||||||
(Clock [cmd: ClockCommand] cmd.delegate(app, Self::Clock)?)
|
(Clock [cmd: ClockCommand] cmd.delegate(app, Self::Clock)?)
|
||||||
|
(Device [cmd: DeviceCommand] cmd.delegate(app, Self::Device)?)
|
||||||
(Editor [cmd: MidiEditCommand] delegate_to_editor(app, cmd)?)
|
(Editor [cmd: MidiEditCommand] delegate_to_editor(app, cmd)?)
|
||||||
(Pool [cmd: PoolCommand] delegate_to_pool(app, cmd)?)
|
(Pool [cmd: PoolCommand] delegate_to_pool(app, cmd)?)
|
||||||
(ToggleHelp [] cmd!(app.toggle_modal(Some(Modal::Help))))
|
(ToggleHelp [] cmd!(app.toggle_modal(Some(Modal::Help))))
|
||||||
|
|
@ -192,10 +212,15 @@ defcom!([self, app: Tek]
|
||||||
(StopAll [] cmd!(app.stop_all())))
|
(StopAll [] cmd!(app.stop_all())))
|
||||||
|
|
||||||
(InputCommand
|
(InputCommand
|
||||||
(Add [] cmd!(app.add_midi_in()?)))
|
(Add [] cmd!(app.midi_in_add()?)))
|
||||||
|
|
||||||
(OutputCommand
|
(OutputCommand
|
||||||
(Add [] cmd!(app.add_midi_out()?)))
|
(Add [] cmd!(app.midi_out_add()?)))
|
||||||
|
|
||||||
|
(DeviceCommand
|
||||||
|
(Picker [] cmd!(app.device_picker_show()))
|
||||||
|
(Pick [i: usize] cmd!(app.device_pick(i)))
|
||||||
|
(Add [i: usize] cmd!(app.device_add(i))))
|
||||||
|
|
||||||
(TrackCommand
|
(TrackCommand
|
||||||
(TogglePlay [] Some(Self::TogglePlay))
|
(TogglePlay [] Some(Self::TogglePlay))
|
||||||
|
|
|
||||||
|
|
@ -383,16 +383,50 @@ impl Tek {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_midi_in (&mut self) -> Usually<()> {
|
pub(crate) fn midi_in_add (&mut self) -> Usually<()> {
|
||||||
self.midi_ins.push(JackMidiIn::new(&self.jack, &format!("M/{}", self.midi_ins.len()), &[])?);
|
self.midi_ins.push(JackMidiIn::new(&self.jack, &format!("M/{}", self.midi_ins.len()), &[])?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_midi_out (&mut self) -> Usually<()> {
|
pub(crate) fn midi_out_add (&mut self) -> Usually<()> {
|
||||||
self.midi_outs.push(JackMidiOut::new(&self.jack, &format!("{}/M", self.midi_outs.len()), &[])?);
|
self.midi_outs.push(JackMidiOut::new(&self.jack, &format!("{}/M", self.midi_outs.len()), &[])?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn device_picker_show (&mut self) {
|
||||||
|
self.modal = Some(Modal::Device(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn device_pick (&mut self, index: usize) {
|
||||||
|
self.modal = Some(Modal::Device(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn device_add (&mut self, index: usize) -> Usually<()> {
|
||||||
|
match index {
|
||||||
|
0 => {
|
||||||
|
let jack = self.jack.clone();
|
||||||
|
self.track_mut()
|
||||||
|
.expect("no active track")
|
||||||
|
.devices
|
||||||
|
.push({
|
||||||
|
let sampler = Sampler::new(&jack, &"sampler", &[], &[&[], &[]], &[&[], &[]])?;
|
||||||
|
Device::Sampler(sampler)
|
||||||
|
});
|
||||||
|
self.modal = None;
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
1 => todo!(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn device_kinds (&self) -> &'static [&'static str] {
|
||||||
|
&[
|
||||||
|
"Sampler",
|
||||||
|
"Plugin (LV2)",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
has_size!(<TuiOut>|self: Tek|&self.size);
|
has_size!(<TuiOut>|self: Tek|&self.size);
|
||||||
|
|
@ -424,6 +458,7 @@ pub trait HasSelection {
|
||||||
pub enum Modal {
|
pub enum Modal {
|
||||||
Help,
|
Help,
|
||||||
Menu,
|
Menu,
|
||||||
|
Device(usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the current user selection in the arranger
|
/// Represents the current user selection in the arranger
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,66 @@ use crate::*;
|
||||||
pub(crate) use std::fmt::Write;
|
pub(crate) use std::fmt::Write;
|
||||||
pub(crate) use ::tengri::tui::ratatui::prelude::Position;
|
pub(crate) use ::tengri::tui::ratatui::prelude::Position;
|
||||||
|
|
||||||
view!(TuiOut: |self: Tek| self.size.of(View(self, self.config.view)); {
|
#[tengri_proc::view(TuiOut)]
|
||||||
":nil" => Box::new("nil"),
|
|
||||||
":modal" => self.view_modal(),
|
|
||||||
":status" => self.view_status(),
|
|
||||||
":transport" => self.view_transport(),
|
|
||||||
":arranger" => self.view_arranger(),
|
|
||||||
":pool" => self.view_pool(),
|
|
||||||
":editor" => self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e)),
|
|
||||||
":samples-keys" => self.sampler().map(|s|s.view_list(false, self.editor().unwrap())),
|
|
||||||
":samples-grid" => self.sampler().map(|s|s.view_grid()),
|
|
||||||
":sample-viewer" => self.sampler().map(|s|s.view_sample(self.editor().unwrap().note_pos())),
|
|
||||||
});
|
|
||||||
|
|
||||||
trait ScenesColors<'a> = Iterator<Item=SceneWithColor<'a>>;
|
|
||||||
|
|
||||||
type SceneWithColor<'a> = (usize, &'a Scene, usize, usize, Option<ItemTheme>);
|
|
||||||
|
|
||||||
impl Tek {
|
impl Tek {
|
||||||
|
|
||||||
pub fn view_modal (&self) -> impl Content<TuiOut> + use<'_> {
|
#[tengri::view(":nil")]
|
||||||
|
fn view_nil (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
"nil"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":status")]
|
||||||
|
fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.update_clock();
|
||||||
|
let cache = self.view_cache.read().unwrap();
|
||||||
|
view_status(
|
||||||
|
self.selected.describe(&self.tracks, &self.scenes),
|
||||||
|
cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":transport")]
|
||||||
|
fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.update_clock();
|
||||||
|
let cache = self.view_cache.read().unwrap();
|
||||||
|
view_transport(
|
||||||
|
self.clock.is_rolling(),
|
||||||
|
cache.bpm.view.clone(), cache.beat.view.clone(), cache.time.view.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":arranger")]
|
||||||
|
fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
ArrangerView::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":pool")]
|
||||||
|
fn view_pool (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":editor")]
|
||||||
|
fn view_editor (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":samples-keys")]
|
||||||
|
fn view_samples_keys (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.sampler().map(|s|s.view_list(false, self.editor().unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":samples-grid")]
|
||||||
|
fn view_samples_grid (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.sampler().map(|s|s.view_grid())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":sample-viewer")]
|
||||||
|
fn view_sample_viewer (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.sampler().map(|s|s.view_sample(self.editor().unwrap().note_pos()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri::view(":modal")]
|
||||||
|
fn view_modal (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
When::new(self.modal.is_some(), Bsp::b(
|
When::new(self.modal.is_some(), Bsp::b(
|
||||||
Fill::xy(Tui::fg_bg(Rgb(64,64,64), Rgb(32,32,32), "")),
|
Fill::xy(Tui::fg_bg(Rgb(64,64,64), Rgb(32,32,32), "")),
|
||||||
Fixed::xy(30, 15, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b(
|
Fixed::xy(30, 15, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b(
|
||||||
|
|
@ -30,6 +70,7 @@ impl Tek {
|
||||||
.enclose(self.modal.map(|modal|match modal {
|
.enclose(self.modal.map(|modal|match modal {
|
||||||
Modal::Menu => self.view_modal_menu().boxed(),
|
Modal::Menu => self.view_modal_menu().boxed(),
|
||||||
Modal::Help => self.view_modal_help().boxed(),
|
Modal::Help => self.view_modal_help().boxed(),
|
||||||
|
Modal::Device(index) => self.view_modal_device(index).boxed(),
|
||||||
}))
|
}))
|
||||||
)))
|
)))
|
||||||
))
|
))
|
||||||
|
|
@ -69,34 +110,14 @@ impl Tek {
|
||||||
Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, bindings, binding)))
|
Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, bindings, binding)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_modal_device (&self, index: usize) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.update_clock();
|
let choices = ||self.device_kinds().iter();
|
||||||
let cache = self.view_cache.read().unwrap();
|
let choice = move|label, i|
|
||||||
view_status(
|
Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) },
|
||||||
self.selected.describe(&self.tracks, &self.scenes),
|
Bsp::e(if i == index { "[ " } else { " " },
|
||||||
cache.sr.view.clone(),
|
Bsp::w(if i == index { " ]" } else { " " },
|
||||||
cache.buf.view.clone(),
|
label))));
|
||||||
cache.lat.view.clone(),
|
Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice))
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
self.update_clock();
|
|
||||||
let cache = self.view_cache.read().unwrap();
|
|
||||||
view_transport(
|
|
||||||
self.clock.is_rolling(),
|
|
||||||
cache.bpm.view.clone(),
|
|
||||||
cache.beat.view.clone(),
|
|
||||||
cache.time.view.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
ArrangerView::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn view_pool (&self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spacing between tracks.
|
/// Spacing between tracks.
|
||||||
|
|
@ -336,8 +357,8 @@ impl<'a> ArrangerView<'a> {
|
||||||
pub(crate) fn devices (&'a self) -> impl Content<TuiOut> + 'a {
|
pub(crate) fn devices (&'a self) -> impl Content<TuiOut> + 'a {
|
||||||
let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self;
|
let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self;
|
||||||
Tryptich::top(1)
|
Tryptich::top(1)
|
||||||
.left(*width_side, button_3("x", "devices", format!("{}", 0), *is_editing))
|
.left(*width_side, button_3("z", "devices", format!("{}", 0), *is_editing))
|
||||||
.right(*width_side, button_2("X", "add device", *is_editing))
|
.right(*width_side, button_2("Z", "add device", *is_editing))
|
||||||
.middle(*width_mid, per_track_top(*width_mid, ||self.tracks_with_sizes_scrolled(),
|
.middle(*width_mid, per_track_top(*width_mid, ||self.tracks_with_sizes_scrolled(),
|
||||||
move|index, track|{
|
move|index, track|{
|
||||||
wrap(if *track_selected == Some(index) {
|
wrap(if *track_selected == Some(index) {
|
||||||
|
|
@ -619,6 +640,10 @@ impl<'a> ArrangerView<'a> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait ScenesColors<'a> = Iterator<Item=SceneWithColor<'a>>;
|
||||||
|
|
||||||
|
type SceneWithColor<'a> = (usize, &'a Scene, usize, usize, Option<ItemTheme>);
|
||||||
|
|
||||||
/// Define a type alias for iterators of sized items (columns).
|
/// Define a type alias for iterators of sized items (columns).
|
||||||
macro_rules! def_sizes_iter {
|
macro_rules! def_sizes_iter {
|
||||||
($Type:ident => $($Item:ty),+) => {
|
($Type:ident => $($Item:ty),+) => {
|
||||||
|
|
|
||||||
2
deps/tengri
vendored
2
deps/tengri
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit 21f7f6b38afc966b7b45af442935d48c8c5067d3
|
Subproject commit b543c43e68154f049019da648064f36af1537434
|
||||||
Loading…
Add table
Add a link
Reference in a new issue