diff --git a/Cargo.toml b/Cargo.toml index 920482ea..0411d666 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ hotpath = ["hotpath/hotpath"] hotpath-cpu = ["hotpath/hotpath-cpu"] hotpath-alloc = ["hotpath/hotpath-alloc"] -arranger = ["port", "editor", "sequencer", "track", "scene", "clip", "select"] +arranger = ["port", "editor", "sequencer", "track", "scene", "clip"] browse = [] clap = [] cli = ["dep:clap"] @@ -75,7 +75,6 @@ pool = [] port = [] sampler = ["port", "meter", "mixer", "browse", "symphonia", "wavers"] scene = [] -select = [] sequencer = ["port", "clock", "uuid", "pool"] sf2 = [] track = [] diff --git a/Justfile b/Justfile index 0d6c64be..4cf8f59d 100644 --- a/Justfile +++ b/Justfile @@ -53,7 +53,7 @@ prof +ARGS="new": tracy +ARGS="new": {{release}} -F prof {{ARGS}} samply +ARGS="new": - samply record target/release/tek {{ARGS}} + samply record -r 8987 target/release/tek {{ARGS}} release := "reset && cargo run --release" release +ARGS="new": diff --git a/src/config.rs b/src/config.rs index dca95edb..4c7abf0a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -38,8 +38,8 @@ pub fn config_load_kind , L: Language> (config: C, src: L) -> U //if let Some(tail) = src.tail()? { match src.head()? { Some("mode") => modes_add(&config.as_ref().modes, src.tail()), - Some("keys") => load_bind(&config.as_ref().binds, src.tail()), - Some("view") => load_view(&config.as_ref().views, src.tail()), + Some("keys") => binds_add(&config.as_ref().binds, src.tail()), + Some("view") => views_add(&config.as_ref().views, src.tail()), _ => return Err(format!("Config::load: expected view/keys/mode expr, got: {src:?}").into()) }?; //} @@ -140,8 +140,8 @@ pub fn mode_add > (mut mode: T, dsl: impl Language) -> Usually }) } -pub fn load_bind <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> { - //println!("\n\rload_bind: {expr:?}"); +pub fn binds_add <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> { + //println!("\n\rbinds_add: {expr:?}"); let name = expr.head()?.ok_or("bind: missing name")?; let body = expr.tail()?.unwrap_or(""); binds.try_write().unwrap().insert(name.into(), { @@ -164,10 +164,10 @@ pub fn load_bind <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> // TODO return Ok(()) } else { - return Err(format!("load_bind: invalid key: {:?}", item.expr()?.head()?).into()) + return Err(format!("binds_add: invalid key: {:?}", item.expr()?.head()?).into()) } } else { - return Err(format!("load_bind: unexpected: {item:?}").into()) + return Err(format!("binds_add: unexpected: {item:?}").into()) })?; map }); @@ -177,15 +177,16 @@ pub fn load_bind <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> /// Configuration: mode, view, and bind definitions. /// /// ``` -/// let source = stringify!( +/// use ::{std::sync::Arc, tek::{Config, modes_add, Mode}}; +/// let config: Config = Default::default(); +/// modes_add(&config.modes, stringify!( /// (mode :menu (name Menu) /// (info Mode selector.) (keys :axis/y :confirm) /// (view (bg (g 0) (bsp/s :ports/out /// (bsp/n :ports/in /// (bg (g 30) (bsp/s (fixed/y 7 :logo) -/// (fill :dialog/menu))))))))); -/// let config: tek::Config = tek::modes_add(tek::Config::default(), source).unwrap(); -/// let mode: tek::Mode = config.get_mode(":menu").unwrap(); +/// (fill :dialog/menu)))))))))).unwrap(); +/// let mode: Arc = config.get_mode(":menu").unwrap(); /// ``` #[derive(Default, Debug)] pub struct Config { @@ -511,7 +512,7 @@ impl View { Some(":device") => draw!(|app|view_device(app)), Some(":dialog") => Self::boxed(move|state, to|draw_dialog(to, word.split("/").skip(1), state)), Some(":sessions") => Self::boxed(move|_, to|view_sessions().draw(to)), - Some(":status") => Self::boxed(move|_, to|"TODO: Status Bar".draw(to)), + Some(":status") => Self::boxed(move|state, to|draw_status_bar(to, state)), Some(":editor") => Self::boxed(move|_, to|"TODO Editor".draw(to)), Some(":transport") => Self::boxed(move|_, to|view_transport(true, "", "", "").draw(to)), Some(":debug") => Self::boxed(move|_, to|format!("[{:?}]", to.area()).exact_h(1).draw(to)), @@ -525,8 +526,12 @@ impl View { } } +pub fn draw_status_bar (to: &mut Tui, state: &App) -> Drawn { + bar(Split::South, 1u16, dim(true, "Mode"), bold(true, &state.mode)).push_x(1).draw(to) +} + /// Load custom view definition. -pub fn load_view <'a> (views: &Views, expr: impl Language) -> UsuallyRef<'a, ()> { +pub fn views_add <'a> (views: &Views, expr: impl Language) -> UsuallyRef<'a, ()> { views.try_write().unwrap().insert( expr.head()?.ok_or("view: missing name")?.into(), View::new(expr.tail()?.ok_or("view: missing body")?)?.into() @@ -637,10 +642,10 @@ mod bind { /// An map of input events (e.g. [TuiEvent]) to [Binding]s. /// /// ``` - /// let lang = stringify!( + /// use ::{std::sync::Arc, tek::{Bind, tengri::TuiEvent}}; + /// let bind = Bind::>::load(&stringify!( /// (@x (nop)) - /// (@y (nop) (nop))); - /// let bind = tek::Bind::>::load(&lang).unwrap(); + /// (@y (nop) (nop)))).unwrap(); /// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1)); /// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2)); /// ``` diff --git a/src/device/arrange/clip.rs b/src/device/arrange/clip.rs index dd728264..9b696434 100644 --- a/src/device/arrange/clip.rs +++ b/src/device/arrange/clip.rs @@ -89,8 +89,12 @@ fn view_scene_name_theme (scene: &Scene, track_index: usize) -> (Arc, ItemT } fn with_clips_size (show: bool, size: &Sizer, content: impl Draw) -> impl Draw { - let wh = east!(size.w() as usize, "x", size.h() as usize); - size.of(above(when(show, fg(Green, wh).align_se().full_wh()), content)) + size.of(above( + when(show, fg(Green, east!( + size.w() as usize, "x", size.h() as usize + )).align_se()), + content.align_c().full_wh() + )) } fn view_scene_bg ( diff --git a/src/device/arrange/scene.rs b/src/device/arrange/scene.rs index 7d77d177..0dd63800 100644 --- a/src/device/arrange/scene.rs +++ b/src/device/arrange/scene.rs @@ -55,10 +55,10 @@ impl Scene { } -#[cfg(all(feature = "select"))] impl_as_ref_opt!(Scene: |self: App| self.project.as_ref_opt()); -#[cfg(all(feature = "select"))] impl_as_mut_opt!(Scene: |self: App| self.project.as_mut_opt()); -#[cfg(all(feature = "select"))] impl_as_ref_opt!(Scene: |self: Arrangement| self.selected_scene()); -#[cfg(all(feature = "select"))] impl_as_mut_opt!(Scene: |self: Arrangement| self.selected_scene_mut()); +impl_as_ref_opt!(Scene: |self: App| self.project.as_ref_opt()); +impl_as_mut_opt!(Scene: |self: App| self.project.as_mut_opt()); +impl_as_ref_opt!(Scene: |self: Arrangement| self.selected_scene()); +impl_as_mut_opt!(Scene: |self: Arrangement| self.selected_scene_mut()); impl + AsMutOpt + Send + Sync> HasScene for T {} @@ -89,12 +89,14 @@ pub trait SceneController: HasScene { todo!() } + #[command(SetZoom = "zoom")] fn scene_set_zoom (&mut self, _size: usize) -> Perhaps where Self: Namespace { todo!() } + #[command(SetName = "name")] fn scene_set_name (&mut self, name: Arc) -> Perhaps where Self: Namespace> @@ -105,6 +107,7 @@ pub trait SceneController: HasScene |name|SceneCommand::SetName { name } )).transpose()?.flatten()) } + #[command(SetColor = "color")] fn scene_set_color (&mut self, color: ItemTheme) -> Perhaps where Self: Namespace @@ -173,6 +176,7 @@ pub trait HasScenes: AsRef> + AsMut> { impl + Namespace + Namespace> @@ -183,6 +187,7 @@ impl + Namespace + Namespace> @@ -196,6 +201,29 @@ pub trait ScenesController: HasScenes Ok(None) } // TODO + + #[command(Select = "select")] + fn scene_select (&mut self) -> Perhaps { + let scenes = self.scenes().len(); + let select = self.selection_mut().select_scene(scenes); + *self.selection_mut() = select; + Ok(None) + } + + #[command(Next = "next")] + fn scene_select_next (&mut self) -> Perhaps { + let scenes = self.scenes().len(); + let select = self.selection().select_scene_next(scenes); + *self.selection_mut() = select; + Ok(None) + } + + #[command(Prev = "prev")] + fn scene_select_prev (&mut self) -> Perhaps { + let select = self.selection_mut().select_scene_prev(); + *self.selection_mut() = select; + Ok(None) + } } pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize + Send + Sync { diff --git a/src/device/arrange/track.rs b/src/device/arrange/track.rs index d9dc1ebf..c3e07c17 100644 --- a/src/device/arrange/track.rs +++ b/src/device/arrange/track.rs @@ -261,6 +261,7 @@ pub trait HasTracks: AsRef> + AsMut> + HasClock + HasTrack impl + Namespace + Namespace> @@ -274,6 +275,7 @@ impl + Namespace + Namespace> @@ -316,6 +318,29 @@ pub trait TracksController: HasTracks let (_index, _) = self.tracks_add_one(None, None, [].into(), [].into())?; Ok(None) } + + #[command(Select = "select")] + fn track_select (&mut self) -> Perhaps { + let tracks = self.tracks().len(); + let select = self.selection_mut().select_track(tracks); + *self.selection_mut() = select; + Ok(None) + } + + #[command(Next = "next")] + fn track_select_next (&mut self) -> Perhaps { + let tracks = self.tracks().len(); + let select = self.selection().select_track_next(tracks); + *self.selection_mut() = select; + Ok(None) + } + + #[command(Prev = "prev")] + fn track_select_prev (&mut self) -> Perhaps { + let select = self.selection_mut().select_track_prev(); + *self.selection_mut() = select; + Ok(None) + } } impl< diff --git a/src/device/editor/piano.rs b/src/device/editor/piano.rs index 36e2b8f2..a2e9d8f4 100644 --- a/src/device/editor/piano.rs +++ b/src/device/editor/piano.rs @@ -139,12 +139,12 @@ impl PianoHorizontal { let buffer = self.buffer.clone(); draw(move|to: &mut Tui|{ let xywh = to.area().into(); - let XYWH(x0, y0, w, _h) = xywh; - let source = buffer.try_read().unwrap(); - //if h as usize != note_axis { - //panic!("area height mismatch: {h} <> {note_axis}"); - //} - if let Tui::Draw(to, ..) = to { + to.buffer().map(|to|{ + let XYWH(x0, y0, w, _h) = xywh; + let source = buffer.try_read().unwrap(); + //if h as usize != note_axis { + //panic!("area height mismatch: {h} <> {note_axis}"); + //} for (area_x, screen_x) in (x0..x0+w).enumerate() { for (area_y, screen_y, _note) in note_y_iter(note_lo, note_hi, y0) { let source_x = time_start + area_x; @@ -163,7 +163,7 @@ impl PianoHorizontal { } } } - } + }); Ok(Some(xywh)) }) } diff --git a/src/device/sampler.rs b/src/device/sampler.rs index 5f568f5c..4f702894 100644 --- a/src/device/sampler.rs +++ b/src/device/sampler.rs @@ -354,7 +354,7 @@ fn draw_viewer (sample: Option<&Arc>>) -> impl Draw + use<'_ lines.push(Line::new(x, min_db, x, y, Color::Green)); t += step / 2.; } - if let Tui::Draw(buf, ..) = to { + to.buffer().map(|buf|{ Canvas::default() .x_bounds([sample.start as f64, sample.end as f64]) .y_bounds([min_db, 0.]) @@ -371,9 +371,9 @@ fn draw_viewer (sample: Option<&Arc>>) -> impl Draw + use<'_ //); }) .render(area, buf); - } + }); } else { - if let Tui::Draw(buf, ..) = to { + to.buffer().map(|buf|{ Canvas::default() .x_bounds([0.0, width as f64]) .y_bounds([0.0, height as f64]) @@ -386,7 +386,7 @@ fn draw_viewer (sample: Option<&Arc>>) -> impl Draw + use<'_ //); }) .render(area, buf); - } + }); } Ok(Some(xywh)) }) diff --git a/src/tek.edn b/src/tek.edn index 37f3a9b4..845c58b8 100644 --- a/src/tek.edn +++ b/src/tek.edn @@ -34,7 +34,7 @@ (mode :scene (keys :scene)) (mode :mix (keys :mix)) (view - (bsp/n (bsp/e :transport :status) + (bar/n 2 (bsp/e :transport :status) (bar/w 2 (align/ne :meters/output) (bar/e 2 (align/nw :meters/input) (full/xy (pad/xy 2 1 (align/c @@ -42,29 +42,37 @@ (bar/s 2 :tracks/devices (bar/s 2 :tracks/names (bar/n 2 :tracks/inputs - (bar/e 16 (bg (g 50) :scenes/names) + (bar/e 12 (bg (g 50) :scenes/names) (align/c :scenes/clips)))))))))))))) -(keys :clock (@space clock/toggle 0) - (@shift/space clock/toggle 0)) - -(keys :color (@c color)) - -(keys :launch (@q launch)) - -(keys :scenes (@shift/S (scenes add)) - (@s (select scene)) - (@up (select scene-dec)) - (@down (select scene-inc))) - -(keys :tracks (@shift/T (tracks add)) - (@t (select track)) - (@left (select track-dec)) - (@right (select track-inc))) - (keys :global (see :history :saveload) - (@f8 dialog :options) - (@f10 dialog :quit)) + (@f8 dialog :options) + (@f10 dialog :quit)) + +(keys :clock + (@space clock/toggle 0) + (@shift/space clock/toggle 0)) + +(keys :color + (@c color)) + +(keys :launch + (@q launch)) + +(keys :scenes + (@shift/S (scenes add)) + (@s (scenes select)) + (@up (scenes prev)) + (@down (scenes next))) + +(keys :tracks + (@shift/T (tracks add)) + (@t (tracks select)) + (@left (tracks prev)) + (@right (tracks next))) + +(keys :clip (see :color :launch :axis/z :axis/z2 :delete) + (@l (toggle :loop))) (view :ports/out (bsp/s (align/w (text L-AUDIO-OUT)) @@ -132,6 +140,7 @@ (keys :axis/w2 (@openbrace dec :w2) (@closebrace inc :w2)) (keys :focus) + (keys :editor (see :axis/i :axis/i2 :axis/y :page :editor/view :editor/add :editor/del)) (keys :editor/view (see :axis/x :axis/x2 :axis/z :axis/z2) @@ -169,8 +178,6 @@ (@r redo 1)) (keys :saveload (@f6 dialog :save) (@f9 dialog :load)) -(keys :clip (see :color :launch :axis/z :axis/z2 :delete) - (@l toggle :loop)) (keys :sequencer (see :color :launch) (@shift/I input/add) (@shift/O output/add)) diff --git a/src/tek.rs b/src/tek.rs index ee414d61..6c099a47 100644 --- a/src/tek.rs +++ b/src/tek.rs @@ -873,7 +873,10 @@ mod draw { let c3 = tui_g(96); let c4 = tui_g(255); bold(true, fg_bg(c1, c2, - east!(fg(c2, "▐"), key, fg(c3, "▐"), when(!hide, fg_bg(c4, c3, label))))) + bar(Split::East, 1u16, fg(c2, "▐"), + bar(Split::East, 1u16, key, + bar(Split::East, 1u16, fg(c3, "▐"), + when(!hide, fg_bg(c4, c3, label))))))) } /// ``` @@ -891,9 +894,10 @@ mod draw { let c3 = tui_g(96); let c4 = tui_g(255); let c5 = tui_g(128); - bold(true, east( + bold(true, bar(Split::East, 3u16, fg_bg(c1, c2, - east(fg(c2, "▐"), east(key, fg(if editing { c5 } else { c3 }, "▐")))), + bar(Split::East, 1u16, fg(c2, "▐"), + bar(Split::East, 1u16, key, fg(if editing { c5 } else { c3 }, "▐")))), east( when(!editing, east(fg_bg(c4, c3, label), fg_bg(c5, c3, "▐"),)), east(fg_bg(tui_g(224), c5, value), fg_bg(c5, Reset, "▌"), )))) diff --git a/tengri b/tengri index b318d498..48aaa393 160000 --- a/tengri +++ b/tengri @@ -1 +1 @@ -Subproject commit b318d498e544fa65bbf3a3ff4dabde166352b045 +Subproject commit 48aaa3933aadd2d795b6652a244fce179d7072bf