mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-07-18 00:06:59 +02:00
restruct: 45e
This commit is contained in:
parent
b3e9cde8a1
commit
027f69cd50
9 changed files with 264 additions and 270 deletions
|
|
@ -3,6 +3,7 @@ pub mod bind; pub use self::bind::*;
|
|||
pub mod cli; pub use self::cli::*;
|
||||
pub mod config; pub use self::config::*;
|
||||
pub mod view; pub use self::view::*;
|
||||
pub mod mode; pub use self::mode::*;
|
||||
|
||||
/// Total application state.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ impl Config {
|
|||
const CONFIG_SUB: &'static str = "v0";
|
||||
const CONFIG: &'static str = "tek.edn";
|
||||
const DEFAULTS: &'static str = include_str!("../tek.edn");
|
||||
|
||||
pub fn watch <T> (callback: impl Fn(Self)->T) -> Usually<T> {
|
||||
let config = Self::init_new(None)?;
|
||||
let result = callback(config);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn init_new (dirs: Option<BaseDirectories>) -> Usually<Self> {
|
||||
let mut config = Self::new(None);
|
||||
config.init()?;
|
||||
|
|
@ -98,95 +105,3 @@ impl Config {
|
|||
self.modes.clone().read().unwrap().get(mode.as_ref()).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn load_mode (modes: &Modes, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
let mut mode = Mode::default();
|
||||
body.each(|item|mode.add(item))?;
|
||||
modes.write().unwrap().insert(name.as_ref().into(), Arc::new(mode));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Collection of interaction modes.
|
||||
pub type Modes = Arc<RwLock<BTreeMap<Arc<str>, Arc<Mode<Arc<str>>>>>>;
|
||||
|
||||
impl Mode<Arc<str>> {
|
||||
/// Add a definition to the mode.
|
||||
///
|
||||
/// Supported definitions:
|
||||
///
|
||||
/// - (name ...) -> name
|
||||
/// - (info ...) -> description
|
||||
/// - (keys ...) -> key bindings
|
||||
/// - (mode ...) -> submode
|
||||
/// - ... -> view
|
||||
///
|
||||
/// ```
|
||||
/// let mut mode: tek::Mode<std::sync::Arc<str>> = Default::default();
|
||||
/// mode.add("(name hello)").unwrap();
|
||||
/// ```
|
||||
pub fn add (&mut self, dsl: impl Language) -> Usually<()> {
|
||||
Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
|
||||
//println!("Mode::add: {head} {:?}", expr.tail());
|
||||
let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
||||
match head {
|
||||
"name" => self.add_name(tail)?,
|
||||
"info" => self.add_info(tail)?,
|
||||
"keys" => self.add_keys(tail)?,
|
||||
"mode" => self.add_mode(tail)?,
|
||||
_ => self.add_view(tail)?,
|
||||
};
|
||||
} else if let Ok(Some(word)) = dsl.word() {
|
||||
self.add_view(word);
|
||||
} else {
|
||||
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
|
||||
})
|
||||
|
||||
//DslParse(dsl, ||Err(format!("Mode::add: unexpected: {dsl:?}").into()))
|
||||
//.word(|word|self.add_view(word))
|
||||
//.expr(|expr|expr.head(|head|{
|
||||
////println!("Mode::add: {head} {:?}", expr.tail());
|
||||
//let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
||||
//match head {
|
||||
//"name" => self.add_name(tail),
|
||||
//"info" => self.add_info(tail),
|
||||
//"keys" => self.add_keys(tail)?,
|
||||
//"mode" => self.add_mode(tail)?,
|
||||
//_ => self.add_view(tail),
|
||||
//};
|
||||
//}))
|
||||
}
|
||||
|
||||
fn add_name (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(dsl.src()?.map(|src|self.name.push(src.into())))
|
||||
}
|
||||
fn add_info (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(dsl.src()?.map(|src|self.info.push(src.into())))
|
||||
}
|
||||
fn add_view (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(dsl.src()?.map(|src|self.view.push(src.into())))
|
||||
}
|
||||
fn add_keys (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(Some(dsl.each(|expr|{ self.keys.push(expr.trim().into()); Ok(()) })?))
|
||||
}
|
||||
fn add_mode (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(Some(if let Some(id) = dsl.head()? {
|
||||
load_mode(&self.modes, &id, &dsl.tail())?;
|
||||
} else {
|
||||
return Err(format!("Mode::add: self: incomplete: {dsl:?}").into());
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Group of view and keys definitions.
|
||||
///
|
||||
/// ```
|
||||
/// let mode = tek::Mode::<std::sync::Arc<str>>::default();
|
||||
/// ```
|
||||
#[derive(Default, Debug)] pub struct Mode<D: Language + Ord> {
|
||||
pub path: PathBuf,
|
||||
pub name: Vec<D>,
|
||||
pub info: Vec<D>,
|
||||
pub view: Vec<D>,
|
||||
pub keys: Vec<D>,
|
||||
pub modes: Modes,
|
||||
}
|
||||
|
|
|
|||
93
src/app/mode.rs
Normal file
93
src/app/mode.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use crate::*;
|
||||
|
||||
pub(crate) fn load_mode (modes: &Modes, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
let mut mode = Mode::default();
|
||||
body.each(|item|mode.add(item))?;
|
||||
modes.write().unwrap().insert(name.as_ref().into(), Arc::new(mode));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Collection of interaction modes.
|
||||
pub type Modes = Arc<RwLock<BTreeMap<Arc<str>, Arc<Mode<Arc<str>>>>>>;
|
||||
|
||||
impl Mode<Arc<str>> {
|
||||
/// Add a definition to the mode.
|
||||
///
|
||||
/// Supported definitions:
|
||||
///
|
||||
/// - (name ...) -> name
|
||||
/// - (info ...) -> description
|
||||
/// - (keys ...) -> key bindings
|
||||
/// - (mode ...) -> submode
|
||||
/// - ... -> view
|
||||
///
|
||||
/// ```
|
||||
/// let mut mode: tek::Mode<std::sync::Arc<str>> = Default::default();
|
||||
/// mode.add("(name hello)").unwrap();
|
||||
/// ```
|
||||
pub fn add (&mut self, dsl: impl Language) -> Usually<()> {
|
||||
Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
|
||||
//println!("Mode::add: {head} {:?}", expr.tail());
|
||||
let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
||||
match head {
|
||||
"name" => self.add_name(tail)?,
|
||||
"info" => self.add_info(tail)?,
|
||||
"keys" => self.add_keys(tail)?,
|
||||
"mode" => self.add_mode(tail)?,
|
||||
_ => self.add_view(tail)?,
|
||||
};
|
||||
} else if let Ok(Some(word)) = dsl.word() {
|
||||
self.add_view(word);
|
||||
} else {
|
||||
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
|
||||
})
|
||||
|
||||
//DslParse(dsl, ||Err(format!("Mode::add: unexpected: {dsl:?}").into()))
|
||||
//.word(|word|self.add_view(word))
|
||||
//.expr(|expr|expr.head(|head|{
|
||||
////println!("Mode::add: {head} {:?}", expr.tail());
|
||||
//let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
||||
//match head {
|
||||
//"name" => self.add_name(tail),
|
||||
//"info" => self.add_info(tail),
|
||||
//"keys" => self.add_keys(tail)?,
|
||||
//"mode" => self.add_mode(tail)?,
|
||||
//_ => self.add_view(tail),
|
||||
//};
|
||||
//}))
|
||||
}
|
||||
|
||||
fn add_name (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(dsl.src()?.map(|src|self.name.push(src.into())))
|
||||
}
|
||||
fn add_info (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(dsl.src()?.map(|src|self.info.push(src.into())))
|
||||
}
|
||||
fn add_view (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(dsl.src()?.map(|src|self.view.push(src.into())))
|
||||
}
|
||||
fn add_keys (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(Some(dsl.each(|expr|{ self.keys.push(expr.trim().into()); Ok(()) })?))
|
||||
}
|
||||
fn add_mode (&mut self, dsl: impl Language) -> Perhaps<()> {
|
||||
Ok(Some(if let Some(id) = dsl.head()? {
|
||||
load_mode(&self.modes, &id, &dsl.tail())?;
|
||||
} else {
|
||||
return Err(format!("Mode::add: self: incomplete: {dsl:?}").into());
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Group of view and keys definitions.
|
||||
///
|
||||
/// ```
|
||||
/// let mode = tek::Mode::<std::sync::Arc<str>>::default();
|
||||
/// ```
|
||||
#[derive(Default, Debug)] pub struct Mode<D: Language + Ord> {
|
||||
pub path: PathBuf,
|
||||
pub name: Vec<D>,
|
||||
pub info: Vec<D>,
|
||||
pub view: Vec<D>,
|
||||
pub keys: Vec<D>,
|
||||
pub modes: Modes,
|
||||
}
|
||||
178
src/app/view.rs
178
src/app/view.rs
|
|
@ -30,7 +30,7 @@ pub fn view_logo () -> impl Draw<Tui> {
|
|||
pub fn view_transport (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw<Tui> {
|
||||
let theme = ItemTheme::G[96];
|
||||
bg(Black, east!(above(
|
||||
wh_full(origin_w(button_play_pause(play))),
|
||||
wh_full(origin_w(button_play_pause(play, false))),
|
||||
wh_full(origin_e(east!(
|
||||
field_h(theme, "BPM", bpm),
|
||||
field_h(theme, "Beat", beat),
|
||||
|
|
@ -56,10 +56,12 @@ pub fn view_status (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl D
|
|||
}
|
||||
|
||||
/// ```
|
||||
/// let _ = tek::button_play_pause(true);
|
||||
/// let _ = tek::button_play_pause(true, true);
|
||||
/// let _ = tek::button_play_pause(true, false);
|
||||
/// let _ = tek::button_play_pause(false, true);
|
||||
/// let _ = tek::button_play_pause(false, false);
|
||||
/// ```
|
||||
pub fn button_play_pause (playing: bool) -> impl Draw<Tui> {
|
||||
let compact = true;//self.is_editing();
|
||||
pub fn button_play_pause (playing: bool, compact: bool) -> impl Draw<Tui> {
|
||||
bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) },
|
||||
either(compact,
|
||||
thunk(move|to: &mut Tui|w_exact(9, either(playing,
|
||||
|
|
@ -202,87 +204,84 @@ pub fn view_io_ports <'a, T: PortsSizes<'a>> (
|
|||
})
|
||||
}
|
||||
|
||||
pub fn view_scenes_clips <'a> (
|
||||
scenes: impl ScenesSizes<'a>,
|
||||
pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> (
|
||||
scenes: impl Fn()->S,
|
||||
tracks: impl TracksSizes<'a>,
|
||||
select: &Selection,
|
||||
editor: Option<&MidiEditor>,
|
||||
size: &Size,
|
||||
is_editing: bool,
|
||||
editing: bool,
|
||||
) -> impl Draw<Tui> {
|
||||
size.of(wh_full(above(wh_full(origin_se(fg(Green, format!("{}x{}", size.w(), size.h())))),
|
||||
thunk(move |to: &mut Tui|{
|
||||
for (index, track, _, _) in tracks {
|
||||
let clips = view_track_clips(&scenes, select, editor, index, track, is_editing);
|
||||
w_exact(track.width as u16, h_full(clips)).draw(to);
|
||||
}
|
||||
Ok(XYWH(0, 0, 0, 0))
|
||||
}))))
|
||||
}
|
||||
let status = wh_full(origin_se(fg(Green, format!("{}x{}", size.w(), size.h()))));
|
||||
let tracks = iter_once(tracks, move|(track_index, track, _, _), _| {
|
||||
let scenes = iter_once(scenes(), move|(scene_index, scene, _, _), _| {
|
||||
let (name, theme): (Arc<str>, ItemTheme) = scene_name_theme(scene, track_index);
|
||||
let f = theme.lightest.term;
|
||||
let (b, o) = scene_bg(theme, select, track_index, scene_index);
|
||||
let w = scene_w(track, select, track_index, editor);
|
||||
let y = scene_y(select, scene_index, editor);
|
||||
let is_selected = scene_sel(select, track_index, scene_index, editing);
|
||||
wh_exact(Some(w), Some(y), below(
|
||||
wh_full(Outer(true, Style::default().fg(o))),
|
||||
wh_full(below(
|
||||
below(
|
||||
fg_bg(o, b, wh_full("")),
|
||||
wh_full(origin_nw(fg_bg(f, b, bold(true, name)))),
|
||||
),
|
||||
wh_full(when(is_selected, editor.map(|e|e.view())))))))
|
||||
});
|
||||
w_exact(track.width as u16, h_full(scenes))
|
||||
});
|
||||
|
||||
pub fn view_track_clips <'a> (
|
||||
scenes: &impl ScenesSizes<'a>,
|
||||
select: &Selection,
|
||||
editor: Option<&MidiEditor>,
|
||||
index: usize,
|
||||
track: &Track,
|
||||
is_editing: bool,
|
||||
) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
return size.of(wh_full(above(status, tracks)));
|
||||
|
||||
for (scene_index, scene, ..) in scenes {
|
||||
|
||||
let (
|
||||
name, theme
|
||||
): (Arc<str>, ItemTheme) = if let Some(Some(clip)) = &scene.clips.get(index) {
|
||||
fn scene_name_theme (scene: &Scene, track_index: usize) -> (Arc<str>, ItemTheme) {
|
||||
if let Some(Some(clip)) = &scene.clips.get(track_index) {
|
||||
let clip = clip.read().unwrap();
|
||||
(format!(" ⏹ {}", &clip.name).into(), clip.color)
|
||||
} else {
|
||||
(" ⏹ -- ".into(), ItemTheme::G[32])
|
||||
};
|
||||
|
||||
let fg = theme.lightest.term;
|
||||
}
|
||||
}
|
||||
|
||||
fn scene_bg (
|
||||
theme: ItemTheme, select: &Selection, track_index: usize, scene_index: usize
|
||||
) -> (Color, Color) {
|
||||
let mut outline = theme.base.term;
|
||||
|
||||
let bg = if select.track() == Some(index) && select.scene() == Some(scene_index) {
|
||||
(if select.track() == Some(track_index) && select.scene() == Some(scene_index) {
|
||||
outline = theme.lighter.term;
|
||||
theme.light.term
|
||||
} else if select.track() == Some(index) || select.scene() == Some(scene_index) {
|
||||
} else if select.track() == Some(track_index) || select.scene() == Some(scene_index) {
|
||||
outline = theme.darkest.term;
|
||||
theme.base.term
|
||||
} else {
|
||||
theme.dark.term
|
||||
};
|
||||
|
||||
let w = if select.track() == Some(index) && let Some(editor) = editor {
|
||||
(editor.size.w() as usize).max(24).max(track.width)
|
||||
} else {
|
||||
track.width
|
||||
} as u16;
|
||||
|
||||
let y = if select.scene() == Some(scene_index) && let Some(editor) = editor {
|
||||
(editor.size.h() as usize).max(12)
|
||||
} else {
|
||||
Self::H_SCENE as usize
|
||||
} as u16;
|
||||
|
||||
let is_selected = is_editing && select.track() == Some(index) && select.scene() == Some(scene_index);
|
||||
|
||||
wh_exact(Some(w), Some(y), below(
|
||||
wh_full(Outer(true, Style::default().fg(outline))),
|
||||
wh_full(below(
|
||||
below(
|
||||
fg_bg(outline, bg, wh_full("")),
|
||||
wh_full(origin_nw(fg_bg(fg, bg, bold(true, &name)))),
|
||||
),
|
||||
wh_full(when(is_selected, editor.map(|e|e.view()))))))
|
||||
).draw(to);
|
||||
|
||||
}, outline)
|
||||
}
|
||||
|
||||
Ok(XYWH(0, 0, 0, 0))
|
||||
})
|
||||
fn scene_w (
|
||||
track: &Track, select: &Selection, track_index: usize, editor: Option<&MidiEditor>
|
||||
) -> u16 {
|
||||
if select.track() == Some(track_index) && let Some(editor) = editor {
|
||||
(editor.size.w() as usize).max(24).max(track.width) as u16
|
||||
} else {
|
||||
track.width as u16
|
||||
}
|
||||
}
|
||||
|
||||
fn scene_y (
|
||||
select: &Selection, scene_index: usize, editor: Option<&MidiEditor>
|
||||
) -> u16 {
|
||||
if select.scene() == Some(scene_index) && let Some(editor) = editor {
|
||||
editor.size.h().max(12)
|
||||
} else {
|
||||
H_SCENE as u16
|
||||
}
|
||||
}
|
||||
|
||||
fn scene_sel (select: &Selection, track_index: usize, scene_index: usize, editing: bool) -> bool {
|
||||
editing && select.track() == Some(track_index) && select.scene() == Some(scene_index)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_track_names (
|
||||
|
|
@ -318,9 +317,7 @@ pub fn view_track_names (
|
|||
}
|
||||
|
||||
pub fn view_track_outputs (
|
||||
theme: ItemTheme,
|
||||
tracks: impl TracksSizes<'_>,
|
||||
midi_outs: impl Iterator<Item = &MidiOutput>,
|
||||
theme: ItemTheme, tracks: impl TracksSizes<'_>, midi_outs: impl Iterator<Item = &MidiOutput>,
|
||||
) -> impl Draw<Tui> {
|
||||
view_track_row_section(theme,
|
||||
south(w_full(origin_w(button_2("o", "utput", false))),
|
||||
|
|
@ -345,9 +342,7 @@ pub fn view_track_outputs (
|
|||
}
|
||||
|
||||
pub fn view_track_inputs (
|
||||
theme: ItemTheme,
|
||||
tracks: impl TracksSizes<'_>,
|
||||
height: u16,
|
||||
theme: ItemTheme, tracks: impl TracksSizes<'_>, height: u16,
|
||||
) -> impl Draw<Tui> {
|
||||
view_track_row_section(theme, button_2("i", "nput", false), button_2("I", "+", false),
|
||||
bg(theme.darker.term, origin_w(thunk(move|to: &mut Tui|{
|
||||
|
|
@ -393,7 +388,7 @@ pub fn view_scene_name (
|
|||
let h = if select.scene() == Some(index) && let Some(_editor) = editor {
|
||||
7
|
||||
} else {
|
||||
Self::H_SCENE as u16
|
||||
H_SCENE as u16
|
||||
};
|
||||
let a = w_full(origin_w(east(format!("·s{index:02} "),
|
||||
fg(g(255), bold(true, &scene.name)))));
|
||||
|
|
@ -442,40 +437,31 @@ pub fn view_per_track () -> impl Draw<Tui> {}
|
|||
pub fn view_per_track_top () -> impl Draw<Tui> {}
|
||||
|
||||
pub fn view_inputs (tracks: impl TracksSizes<'_>, midi_ins: &[MidiInput]) -> impl Draw<Tui> {
|
||||
let header = h_exact(1, view_inputs_header(tracks, midi_ins));
|
||||
south(header, thunk(move |to: &mut Tui|{
|
||||
for (index, port) in midi_ins.iter().enumerate() {
|
||||
x_push(index as u16 * 10, h_exact(1, view_inputs_row(tracks, port))).draw(to);
|
||||
}
|
||||
todo!()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn view_inputs_header (tracks: impl TracksSizes<'_>, midi_ins: &[MidiInput]) -> impl Draw<Tui> {
|
||||
east(w_exact(20, origin_w(button_3("i", "nput ", format!("{}", midi_ins.len()), false))),
|
||||
west(w_exact(4, button_2("I", "+", false)), thunk(move|to: &mut Tui|{
|
||||
let title_1 = wh_exact(Some(20), Some(1), origin_w(button_3("i", "nput ", format!("{}", midi_ins.len()), false)));
|
||||
let title_2 = wh_exact(Some(4), Some(1), w_exact(4, button_2("I", "+", false)));
|
||||
east(title_1, west(title_2, thunk(move|to: &mut Tui|{
|
||||
for (_index, track, x1, _x2) in tracks {
|
||||
#[cfg(feature = "track")]
|
||||
south(
|
||||
x_push(x1 as u16, bg(track.color.dark.term, origin_w(w_exact(track.width as u16, east!(
|
||||
either(track.sequencer.monitoring, fg(Green, "mon "), "mon "),
|
||||
either(track.sequencer.recording, fg(Red, "rec "), "rec "),
|
||||
either(track.sequencer.overdub, fg(Yellow, "dub "), "dub "),
|
||||
))))).draw(to);
|
||||
}
|
||||
todo!()
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn view_inputs_row (tracks: impl TracksSizes<'_>, port: &MidiInput) -> impl Draw<Tui> {
|
||||
east(w_exact(20, origin_w(east(" ● ", bold(true, fg(Rgb(255,255,255), port.port_name()))))),
|
||||
))))),
|
||||
thunk(move |to: &mut Tui|{
|
||||
for (index, port) in midi_ins.iter().enumerate() {
|
||||
x_push(index as u16 * 10, h_exact(1, east(w_exact(20, origin_w(east(" ● ", bold(true, fg(Rgb(255,255,255), port.port_name()))))),
|
||||
west(w_exact(4, ()), thunk(move|to: &mut Tui|{
|
||||
for (_index, track, _x1, _x2) in tracks {
|
||||
#[cfg(feature = "track")]
|
||||
bg(track.color.darker.term, origin_w(w_exact(track.width as u16, east!(
|
||||
either(track.sequencer.monitoring, fg(Green, " ● "), " · "),
|
||||
either(track.sequencer.recording, fg(Red, " ● "), " · "),
|
||||
either(track.sequencer.overdub, fg(Yellow, " ● "), " · "),
|
||||
)))).draw(to);
|
||||
todo!()
|
||||
}))))).draw(to);
|
||||
}
|
||||
todo!()
|
||||
})
|
||||
).draw(to);
|
||||
}
|
||||
todo!()
|
||||
})))
|
||||
|
|
@ -539,14 +525,14 @@ pub fn view_outputs (
|
|||
|
||||
pub fn view_track_devices (
|
||||
theme: ItemTheme,
|
||||
tracks: &impl TracksSizes<'_>,
|
||||
tracks: impl TracksSizes<'_>,
|
||||
track: Option<&Track>,
|
||||
h: u16,
|
||||
) -> impl Draw<Tui> {
|
||||
view_track_row_section(theme,
|
||||
button_3("d", "evice", format!("{}", track.map(|t|t.devices.len()).unwrap_or(0)), false),
|
||||
button_2("D", "+", false),
|
||||
iter(tracks, move|(_, track, _x1, _x2), index| wh_exact(
|
||||
iter_once(tracks, move|(_, track, _x1, _x2), index| wh_exact(
|
||||
Some(track_width(index, track)),
|
||||
Some(h + 1),
|
||||
bg(track.color.dark.term, origin_nw(iter_south(move||0..h,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ pub trait ClipsView: TracksView + ScenesView {
|
|||
/// Draw clips per scene
|
||||
fn view_scenes_clips <'a> (&'a self) -> impl Draw<Tui> + 'a {
|
||||
crate::view::view_scenes_clips(
|
||||
self.scenes_with_sizes(),
|
||||
||self.scenes_with_sizes(),
|
||||
self.tracks_with_sizes(),
|
||||
self.selection(),
|
||||
self.editor(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
use crate::*;
|
||||
|
||||
/// Default scene height.
|
||||
pub const H_SCENE: usize = 2;
|
||||
|
||||
/// Default editor height.
|
||||
pub const H_EDITOR: usize = 15;
|
||||
|
||||
/// A scene consists of a set of clips to play together.
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -51,10 +57,6 @@ impl Scene {
|
|||
}
|
||||
|
||||
pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize + Send + Sync {
|
||||
/// Default scene height.
|
||||
const H_SCENE: usize = 2;
|
||||
/// Default editor height.
|
||||
const H_EDITOR: usize = 15;
|
||||
fn h_scenes (&self) -> u16;
|
||||
fn w_side (&self) -> u16;
|
||||
fn w_mid (&self) -> u16;
|
||||
|
|
@ -70,7 +72,7 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize +
|
|||
let height = if self.selection().scene() == Some(s) && self.editor().is_some() {
|
||||
8
|
||||
} else {
|
||||
Self::H_SCENE
|
||||
H_SCENE
|
||||
};
|
||||
if y + height <= self.clips_size().h() as usize {
|
||||
let data = (s, scene, y, y + height);
|
||||
|
|
|
|||
|
|
@ -223,71 +223,66 @@ impl HasTrackScroll for Arrangement {
|
|||
|
||||
def_command!(TrackCommand: |track: Track| {
|
||||
Stop => { track.sequencer.enqueue_next(None); Ok(None) },
|
||||
SetRec { rec: Option<bool> } => toggle_bool(&mut track.sequencer.recording, rec, |rec|Self::SetRec { rec }),
|
||||
SetMon { mon: Option<bool> } => toggle_bool(&mut track.sequencer.monitoring, mon, |mon|Self::SetMon { mon }),
|
||||
SetMute { mute: Option<bool> } => todo!(),
|
||||
SetSolo { solo: Option<bool> } => todo!(),
|
||||
SetSize { size: usize } => todo!(),
|
||||
SetZoom { zoom: usize } => todo!(),
|
||||
SetName { name: Arc<str> } =>
|
||||
swap_value(&mut track.name, name, |name|Self::SetName { name }),
|
||||
SetColor { color: ItemTheme } =>
|
||||
swap_value(&mut track.color, color, |color|Self::SetColor { color }),
|
||||
SetRec { rec: Option<bool> } =>
|
||||
toggle_bool(&mut track.sequencer.recording, rec, |rec|Self::SetRec { rec }),
|
||||
SetMon { mon: Option<bool> } =>
|
||||
toggle_bool(&mut track.sequencer.monitoring, mon, |mon|Self::SetMon { mon }),
|
||||
SetName { name: Arc<str> } => swap_value(&mut track.name, name, |name|Self::SetName { name }),
|
||||
SetColor { color: ItemTheme } => swap_value(&mut track.color, color, |color|Self::SetColor { color }),
|
||||
});
|
||||
|
||||
impl<T: AsRef<Vec<Track>>+AsMut<Vec<Track>>> HasTracks for T {}
|
||||
impl<T: AsRefOpt<Track>+AsMutOpt<Track>+Send+Sync> HasTrack for T {}
|
||||
impl<T: ScenesView+HasMidiIns+HasMidiOuts+HasTrackScroll> TracksView for T {}
|
||||
impl_has!(Vec<Track>: |self: Arrangement| self.tracks);
|
||||
impl_as_ref_opt!(Track: |self: Arrangement| self.selected_track());
|
||||
impl_as_mut_opt!(Track: |self: Arrangement| self.selected_track_mut());
|
||||
impl_as_ref!(Vec<Track>: |self: App| self.project.as_ref());
|
||||
impl_as_mut!(Vec<Track>: |self: App| self.project.as_mut());
|
||||
#[cfg(feature = "select")] impl_as_ref_opt!(Track: |self: App| self.project.as_ref_opt());
|
||||
#[cfg(feature = "select")] impl_as_mut_opt!(Track: |self: App| self.project.as_mut_opt());
|
||||
impl_has!(Vec<Track>: |self: Arrangement| self.tracks);
|
||||
impl_as_ref_opt!(Track: |self: Arrangement| self.selected_track());
|
||||
impl_as_mut_opt!(Track: |self: Arrangement| self.selected_track_mut());
|
||||
|
||||
impl Arrangement {
|
||||
#[cfg(feature = "track")]
|
||||
|
||||
pub fn view_inputs (&self, _theme: ItemTheme) -> impl Draw<Tui> + '_ {
|
||||
crate::view::view_inputs(self.tracks_with_sizes(), self.midi_ins().as_slice())
|
||||
crate::view::view_inputs(
|
||||
self.tracks_with_sizes(), self.midi_ins().as_slice()
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
pub fn view_inputs_header (&self) -> impl Draw<Tui> + '_ {
|
||||
crate::view::view_inputs_header(self.tracks_with_sizes(), self.midi_ins().as_slice())
|
||||
}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
pub fn view_inputs_row (&self, port: &MidiInput) -> impl Draw<Tui> {
|
||||
crate::view::view_inputs_row(port)
|
||||
}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
pub fn view_outputs (&self, theme: ItemTheme) -> impl Draw<Tui> {
|
||||
crate::view::view_outputs(
|
||||
theme, self.tracks_with_sizes(), self.midi_outs(), self.outputs_height()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<Tui> {
|
||||
crate::view::view_track_devices(
|
||||
theme, self.tracks_with_sizes(), self.track(), self.devices_height()
|
||||
)
|
||||
}
|
||||
|
||||
fn devices_height (&self) -> u16 {
|
||||
let mut h = 2;
|
||||
for track in self.tracks().iter() {
|
||||
h = h.max(track.devices.len() * 2);
|
||||
}
|
||||
h as u16
|
||||
}
|
||||
|
||||
fn outputs_height (&self) -> u16 {
|
||||
let mut h = 1;
|
||||
for output in self.midi_outs().iter() {
|
||||
h += 1 + output.connections.len();
|
||||
}
|
||||
let h = h as u16;
|
||||
crate::view::view_outputs(self.tracks_with_sizes())
|
||||
}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
pub fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<Tui> {
|
||||
let mut h = 2u16;
|
||||
for track in self.tracks().iter() {
|
||||
h = h.max(track.devices.len() as u16 * 2);
|
||||
}
|
||||
crate::view::view_track_devices(||self.tracks_with_sizes(), self.track(), h)
|
||||
h as u16
|
||||
}
|
||||
|
||||
/// Add multiple tracks
|
||||
#[cfg(feature = "track")] pub fn tracks_add (
|
||||
&mut self,
|
||||
count: usize, width: Option<usize>,
|
||||
mins: &[Connect], mouts: &[Connect],
|
||||
pub fn tracks_add (
|
||||
&mut self, count: usize, width: Option<usize>, mins: &[Connect], mouts: &[Connect],
|
||||
) -> Usually<()> {
|
||||
let track_color_1 = ItemColor::random();
|
||||
let track_color_2 = ItemColor::random();
|
||||
|
|
@ -302,10 +297,12 @@ impl Arrangement {
|
|||
}
|
||||
|
||||
/// Add a track
|
||||
#[cfg(feature = "track")] pub fn track_add (
|
||||
pub fn track_add (
|
||||
&mut self,
|
||||
name: Option<&str>, color: Option<ItemTheme>,
|
||||
mins: &[Connect], mouts: &[Connect],
|
||||
name: Option<&str>,
|
||||
color: Option<ItemTheme>,
|
||||
mins: &[Connect],
|
||||
mouts: &[Connect],
|
||||
) -> Usually<(usize, &mut Track)> {
|
||||
let name: Arc<str> = name.map_or_else(
|
||||
||format!("trk{:02}", self.track_last).into(),
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ pub(crate) use tengri::{
|
|||
#[cfg(feature = "cli")]
|
||||
pub fn main () -> Usually<()> {
|
||||
Config::watch(|config|{
|
||||
Exit::enter(|exit|{
|
||||
Jack::connect("tek", |jack|{
|
||||
let project = Arrangement::new(&jack, &Clock::new(&jack, 51));
|
||||
Exit::run(|exit|{
|
||||
Jack::new_run("tek", |jack|{
|
||||
let project = Arrangement::new(&jack, &Clock::new(&jack, Some(51.)));
|
||||
let state = App::new_shared(jack, config, project, ":menu");
|
||||
let keyboard = tui_input(&exit, &state, Duration::from_millis(100))?;
|
||||
let terminal = tui_output(&exit, &state, Duration::from_millis(10))?;
|
||||
|
|
|
|||
2
tengri
2
tengri
|
|
@ -1 +1 @@
|
|||
Subproject commit e0781571c42cb72e7445a2adbdb7a99e37600562
|
||||
Subproject commit 0273d2ac75b8a144ea03b4bdd94d08003f3589df
|
||||
Loading…
Add table
Add a link
Reference in a new issue