diff --git a/Justfile b/Justfile index e91a5c36..5ecece41 100644 --- a/Justfile +++ b/Justfile @@ -64,7 +64,7 @@ arranger-ext: arranger-release: {{release}} {{name}} {{bpm}} arranger arranger-release-ext: - {{release}} {{name}} {{bpm}} {{midi-in}} {{firefox-in}} {{midi-out}} arranger + {{release}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} arranger groovebox: {{debug}} {{name}} {{bpm}} groovebox diff --git a/config/config_arranger.edn b/config/config_arranger.edn index 8ac29f05..a83b8521 100644 --- a/config/config_arranger.edn +++ b/config/config_arranger.edn @@ -22,10 +22,10 @@ (bsp/w :view-meters-output (bsp/e :view-meters-input (bsp/n (fixed/y 2 :view-status-h2) - (bsp/n :view-tracks-inputs - (bsp/s :view-tracks-devices - (bsp/s :view-tracks-outputs - (bsp/s :view-tracks-names + (bsp/n (fill/x (align/w :view-tracks-inputs)) + (bsp/s (fill/x (align/w :view-tracks-devices)) + (bsp/s (fill/x (align/w :view-tracks-outputs)) + (bsp/s (fill/x (align/w :view-tracks-names)) (fill/xy (either :is-editing - (bsp/e :view-scenes-names :view-editor) + (bsp/e (fixed/x 20 :view-scenes-names) :view-editor) :view-scenes))))))))))) diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 5553da0e..5ede40e6 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -435,8 +435,7 @@ impl Configuration { return Err(format!("(e4) unexpected non-symbol {next:?}").into()) }; - let token = exp.peek(); - if let Some(Token { value: Value::Str(path), .. }) = token { + if let Some(Token { value: Value::Str(path), .. }) = exp.peek() { let path = base.as_ref().parent().unwrap().join(unquote(path)); if !std::fs::exists(&path)? { return Err(format!("(e5) not found: {path:?}").into()) @@ -449,11 +448,7 @@ impl Configuration { map.add_layer_if( Box::new(move |state|{ let mut exp = exp.clone(); - let value = Context::get(state, &mut format!(":{cond}").as_str().into()).unwrap_or(false); - if value { - panic!("layer-if cond={cond:?} exp={exp:?} value={value:?}"); - } - value + Context::get(state, &mut exp).unwrap_or(false) }), keys ); diff --git a/crates/app/src/view.rs b/crates/app/src/view.rs index dc93ffce..1a67e193 100644 --- a/crates/app/src/view.rs +++ b/crates/app/src/view.rs @@ -123,14 +123,13 @@ impl App { self.project.view_scenes_clips() } pub fn view_tracks_inputs <'a> (&'a self) -> impl Content + use<'a> { - Fixed::y(1 + self.project.midi_ins.len() as u16, - self.project.view_inputs(self.color)) + Fixed::y(1 + self.project.midi_ins.len() as u16, self.project.view_inputs(self.color)) } pub fn view_tracks_outputs <'a> (&'a self) -> impl Content + use<'a> { - self.project.view_outputs(self.color) + Fixed::y(1 + self.project.midi_outs.len() as u16, self.project.view_outputs(self.color)) } pub fn view_tracks_devices <'a> (&'a self) -> impl Content + use<'a> { - Fixed::y(4, self.project.view_track_devices(self.color)) + Fixed::y(3, self.project.view_track_devices(self.color)) } pub fn view_tracks_names <'a> (&'a self) -> impl Content + use<'a> { Fixed::y(2, self.project.view_track_names(self.color)) diff --git a/crates/device/src/arranger/arranger_api.rs b/crates/device/src/arranger/arranger_api.rs index 07377856..46043485 100644 --- a/crates/device/src/arranger/arranger_api.rs +++ b/crates/device/src/arranger/arranger_api.rs @@ -39,14 +39,6 @@ impl ArrangementCommand { } } }; - if let Some(editor) = arranger.editor.as_mut() { - if let Some(clip) = editor.clip() { - let length = clip.read().unwrap().length.max(1); - let width = arranger.inner_size.w().saturating_sub(20).max(1); - editor.set_time_zoom(length / width); - editor.redraw(); - } - } Ok(None) } /// Set the selection diff --git a/crates/device/src/arranger/arranger_view.rs b/crates/device/src/arranger/arranger_view.rs index c9ebc98a..55cc5198 100644 --- a/crates/device/src/arranger/arranger_view.rs +++ b/crates/device/src/arranger/arranger_view.rs @@ -2,98 +2,91 @@ use crate::*; impl Arrangement { pub fn view_inputs <'a> (&'a self, theme: ItemTheme) -> impl Content + 'a { - let mut h = 1u16; + let mut h = 0; for track in self.tracks().iter() { h = h.max(self.midi_ins.len() as u16); } let h = h + 1; - Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ - add(&Fixed::y(1, - Bsp::e(Fixed::x(20, Align::w(button_3("i", "nput ", format!("{}", self.midi_ins.len()), false))), - Bsp::w(Fixed::x(4, button_2("I", "+", false)), - Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ - for (index, track, x1, x2) in self.tracks_with_sizes() { - add(&Tui::bg(track.color.dark.rgb, Align::w(Fixed::x(track.width as u16, row!( - Either(track.sequencer.monitoring, Tui::fg(Green, "mon "), "mon "), - Either(track.sequencer.recording, Tui::fg(Red, "rec "), "rec "), - Either(track.sequencer.overdub, Tui::fg(Yellow, "dub "), "dub "), - ))))) - } - }))))); - for (index, port) in self.midi_ins().iter().enumerate() { - add(&Fixed::y(1, Bsp::e( - Fixed::x(20, Align::w(Bsp::e(" ● ", Tui::bold(true, Tui::fg(Rgb(255,255,255),port.name()))))), - Bsp::w(Fixed::x(4, ()), - Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ - for (index, track, x1, x2) in self.tracks_with_sizes() { - add(&Tui::bg(track.color.darker.rgb, Align::w(Fixed::x(track.width as u16, row!( - Either(track.sequencer.monitoring, Tui::fg(Green, " ● "), " · "), - Either(track.sequencer.recording, Tui::fg(Red, " ● "), " · "), - Either(track.sequencer.overdub, Tui::fg(Yellow, " ● "), " · "), - ))))) - } - }))))); - } - }) - } - pub fn view_outputs <'a> (&'a self, theme: ItemTheme) -> impl Content + 'a { - let mut h = 1; - for output in self.midi_outs().iter() { - h += 1 + output.conn().len(); - } - let h = h as u16; - let list = Bsp::s( - Fixed::y(1, Fill::x(Align::w(button_3("o", "utput", format!("{}", self.midi_outs.len()), false)))), - Fixed::y(h - 1, Fill::xy(Align::nw(Stack::south(|add: &mut dyn FnMut(&dyn Render)|{ - for (index, port) in self.midi_outs().iter().enumerate() { - add(&Fixed::y(1,Fill::x(Bsp::e( - Align::w(Bsp::e(" ● ", Tui::fg(Rgb(255,255,255),Tui::bold(true, port.name())))), - Fill::x(Align::e(format!("{}/{} ", - port.port().get_connections().len(), - port.conn().len()))))))); - for (index, conn) in port.conn().iter().enumerate() { - add(&Fixed::y(1, Fill::x(Align::w(format!(" c{index:02}{}", conn.info()))))); + self.view_track_row_section( + theme, + Bsp::s( + Fixed::y(1, Fill::x(Align::w(button_3("i", "nput ", format!("{}", self.midi_ins.len()), false)))), + Fixed::y(h - 1, Fill::x(Align::nw(Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ + for (index, port) in self.midi_ins.iter().enumerate() { + add(&Fill::x(Align::w(format!("·i{index:02} {}", port.name())))); } - } - }))))); - Fixed::y(h, self.view_track_row_section(theme, list, button_2("O", "+", false), + }))))), + button_2("I", "+", false), Tui::bg(theme.darker.rgb, Align::w(Fill::x( Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ for (index, track, x1, x2) in self.tracks_with_sizes() { add(&Fixed::x(self.track_width(index, track), Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ let index = 0; - add(&Fixed::y(1, Align::w(Bsp::e( - Either(true, Tui::fg(Green, "play "), "play "), - Either(false, Tui::fg(Yellow, "solo "), "solo "), - )))); + add(&Fixed::y(1, track.sequencer.midi_ins.get(0).map(|port| + Tui::fg_bg(Rgb(255, 255, 255), track.color.base.rgb, + Fill::x(Align::w(format!("·i{index:02} {}", port.name()))))))); + for (index, port) in self.midi_ins().iter().enumerate() { + add(&Fixed::y(1, Align::w(row!( + Either(track.sequencer.monitoring, Tui::fg(Green, "●mon "), "·mon "), + Either(track.sequencer.recording, Tui::fg(Red, "●rec "), "·rec "), + Either(track.sequencer.overdub, Tui::fg(Yellow, "●dub "), "·dub "), + )))); + } + })))}}))))) + } + pub fn view_outputs <'a> (&'a self, theme: ItemTheme) -> impl Content + 'a { + let mut h = 1u16; + for track in self.tracks().iter() { + h = h.max(track.sequencer.midi_outs.len() as u16); + } + let h = h + 1; + self.view_track_row_section( + theme, + Bsp::s( + Fixed::y(1, Fill::x(Align::w(button_3("o", "utput", format!("{}", self.midi_outs.len()), false)))), + Fixed::y(h - 1, Fill::xy(Align::nw(Stack::south(|add: &mut dyn FnMut(&dyn Render)|{ + for (index, port) in self.midi_outs().iter().enumerate() { + add(&Fill::x(Align::w(format!("·o{index:02} {}", port.name())))); + } + }))))), + button_2("O", "+", false), + Tui::bg(theme.darker.rgb, Align::w(Fill::x( + Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ + for (index, track, x1, x2) in self.tracks_with_sizes() { + add(&Fixed::x(self.track_width(index, track), + Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ + let index = 0; + add(&Fixed::y(1, track.sequencer.midi_outs.get(0).map(|port| + Tui::fg_bg(Rgb(255, 255, 255), track.color.base.rgb, + Fill::x(Align::w(format!("·o{index:02} {}", port.name()))))))); for (index, port) in self.midi_outs().iter().enumerate() { add(&Fixed::y(1, Align::w(Bsp::e( - Either(true, Tui::fg(Green, " ● "), " · "), - Either(false, Tui::fg(Yellow, " ● "), " · "), + Either(true, Tui::fg(Green, "●play "), "·play "), + Either(false, Tui::fg(Yellow, "●solo "), "·solo "), )))); - for (index, conn) in port.conn().iter().enumerate() { - add(&Fixed::y(1, Fill::x(""))); - } - }})))}})))))) + } + }))); + } + }))))) } pub fn view_track_devices <'a> (&'a self, theme: ItemTheme) -> impl Content + 'a { let mut h = 2u16; for track in self.tracks().iter() { - h = h.max(track.devices.len() as u16 * 2); + h = h.max(track.devices.len() as u16); } self.view_track_row_section( theme, - button_3("d", "evice", format!("{}", self.track().map(|t|t.devices.len()).unwrap_or(0)), false), + button_3("d", "evice", format!("{}", self.track().map(|t|t.devices.len()).unwrap_or(0)), false), button_2("D", "+", false), - Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ - for (index, track, x1, x2) in self.tracks_with_sizes() { - add(&Fixed::xy(self.track_width(index, track), h + 1, - Tui::bg(track.color.dark.rgb, Align::nw(Map::south(2, move||0..h, - |_, index|Fixed::xy(track.width as u16, 2, Tui::bg(ItemTheme::G[32].base.rgb, - Align::nw(format!(" · {}", "--"))))))))); - } - })) + Fixed::y(h, Tui::bg(theme.darker.rgb, Align::w(Fill::x(Stack::east( + move|add: &mut dyn FnMut(&dyn Render)|{ + for (index, track, x1, x2) in self.tracks_with_sizes() { + add(&Fixed::xy(self.track_width(index, track), h + 1, + Tui::bg(track.color.dark.rgb, Align::nw(Map::south(1, move||0..h, + |_, index|format!("·d{index:02} {}", "--------")))))); + } + })))))) } } @@ -142,10 +135,15 @@ pub trait TracksView: theme: ItemTheme, button: impl Content, button_add: impl Content, - content: impl Content + content: impl Content ) -> impl Content { - Bsp::w(Fill::y(Fixed::x(4, Align::nw(button_add))), - Bsp::e(Fixed::x(20, Fill::y(Align::nw(button))), Fill::xy(Align::c(content)))) + Bsp::w( + Fill::y(Fixed::x(4, Align::nw(button_add))), + Bsp::e( + Fixed::x(20, Fill::y(Align::nw(button))), + Fill::xy(Align::c(content)) + ) + ) } fn view_track_header <'a, T: Content> ( &'a self, theme: ItemTheme, content: T @@ -214,7 +212,7 @@ pub trait TracksView: } self.view_track_row_section( theme, - button_2("i", "nput", false), + button_2("i", "nput", false), button_2("I", "+", false), Tui::bg(theme.darker.rgb, Align::w(Fill::x( Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ @@ -233,7 +231,13 @@ pub trait TracksView: }}))))) } fn track_width (&self, index: usize, track: &Track) -> u16 { - track.width as u16 + (if self.selection().track() == Some(index) + && let Some(editor) = self.editor() + { + editor.width().max(24).max(track.width) + } else { + track.width + }) as u16 } } @@ -243,7 +247,7 @@ pub trait ScenesView: HasSceneScroll + HasClipsSize + Send + - Sync + Sync { /// Default scene height. const H_SCENE: usize = 2; @@ -253,13 +257,15 @@ pub trait ScenesView: fn w_side (&self) -> u16; fn w_mid (&self) -> u16; fn scenes_with_sizes (&self) -> impl ScenesSizes<'_> { + let editing = self.editor().is_some(); + let height = Self::H_SCENE; + let larger = 8;//FIXME//self.editor().map(|e|e.height()).unwrap_or(Self::H_SCENE); + let selected_track = self.selection().track(); + let selected_scene = self.selection().scene(); let mut y = 0; self.scenes().iter().enumerate().skip(self.scene_scroll()).map_while(move|(s, scene)|{ - let height = if self.selection().scene() == Some(s) && self.editor().is_some() { - 8 - } else { - Self::H_SCENE - }; + let active = editing && selected_track.is_some() && selected_scene == Some(s); + let height = if active { larger } else { height }; if y + height <= self.clips_size().h() { let data = (s, scene, y, y + height); y += height; @@ -270,15 +276,15 @@ pub trait ScenesView: }) } fn view_scenes_names (&self) -> impl Content { - Fixed::x(20, Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ + Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ for (index, scene, ..) in self.scenes_with_sizes() { add(&self.view_scene_name(index, scene)); } - })) + }) } fn view_scene_name (&self, index: usize, scene: &Scene) -> impl Content { let h = if self.selection().scene() == Some(index) && let Some(editor) = self.editor() { - 7 + (editor.height() as u16).max(12) } else { Self::H_SCENE as u16 }; @@ -315,7 +321,13 @@ pub trait ClipsView: for (track_index, track, _, _) in self.tracks_with_sizes() { //column(&Fixed::x(5, Fill::xy(Tui::bg(Green, "kyp")))); column(&Fixed::x( - track.width as u16, + if self.selection().track() == Some(track_index) + && let Some(editor) = self.editor() + { + editor.width().max(24).max(track.width) + } else { + track.width + } as u16, Fill::y(self.view_track_clips(track_index, track)) )) } diff --git a/crates/device/src/editor/editor_view.rs b/crates/device/src/editor/editor_view.rs index c553cdfc..7e0c9661 100644 --- a/crates/device/src/editor/editor_view.rs +++ b/crates/device/src/editor/editor_view.rs @@ -13,15 +13,9 @@ impl MidiEditor { (clip.color, clip.name.clone(), clip.length, clip.looped) } else { (ItemTheme::G[64], String::new().into(), 0, false) }; Fixed::x(20, col!( - Fill::x(Align::w(Bsp::e( - button_2("f2", "name ", false), - Fill::x(Align::e(Tui::fg(Rgb(255, 255, 255), format!("{name} "))))))), - Fill::x(Align::w(Bsp::e( - button_2("l", "ength ", false), - Fill::x(Align::e(Tui::fg(Rgb(255, 255, 255), format!("{length} "))))))), - Fill::x(Align::w(Bsp::e( - button_2("r", "epeat ", false), - Fill::x(Align::e(Tui::fg(Rgb(255, 255, 255), format!("{looped} "))))))), + Fill::x(Align::w(Bsp::e(" Clip ", format!("{name}")))), + Fill::x(Align::w(Bsp::e(" Length ", format!("{length}")))), + Fill::x(Align::w(Bsp::e(" Loop ", looped.to_string()))), )) } @@ -37,18 +31,9 @@ impl MidiEditor { let note_pos = format!("{:>3}", note_pos); let note_len = format!("{:>4}", self.get_note_len()); Fixed::x(20, col!( - Fill::x(Align::w(Bsp::e( - button_2("t", "ime ", false), - Fill::x(Align::e(Tui::fg(Rgb(255, 255, 255), - format!("{length} /{time_zoom} +{time_pos} "))))))), - Fill::x(Align::w(Bsp::e( - button_2("z", "lock ", false), - Fill::x(Align::e(Tui::fg(Rgb(255, 255, 255), - format!("{time_lock}"))))))), - Fill::x(Align::w(Bsp::e( - button_2("x", "note ", false), - Fill::x(Align::e(Tui::fg(Rgb(255, 255, 255), - format!("{note_name} {note_pos} {note_len}"))))))), + Fill::x(Align::w(Bsp::e(" Time ", format!("{length}/{time_zoom}+{time_pos}")))), + Fill::x(Align::w(Bsp::e(" Lock ", format!("{time_lock}")))), + Fill::x(Align::w(Bsp::e(" Note ", format!("{note_name} {note_pos} {note_len}")))), )) } diff --git a/crates/device/src/lib.rs b/crates/device/src/lib.rs index a4ca5930..6041e16c 100644 --- a/crates/device/src/lib.rs +++ b/crates/device/src/lib.rs @@ -38,42 +38,3 @@ mod dialog; pub use self::dialog::*; #[cfg(feature = "vst2")] mod vst2; #[cfg(feature = "vst2")] pub use self::vst2::*; #[cfg(feature = "vst3")] mod vst3; #[cfg(feature = "vst3")] pub use self::vst3::*; #[cfg(feature = "clap")] mod clap; #[cfg(feature = "clap")] pub use self::clap::*; - -pub fn button_2 <'a> ( - key: impl Content + 'a, label: impl Content + 'a, editing: bool, -) -> impl Content + 'a { - let key = Tui::fg_bg(Tui::orange(), Tui::g(0), Bsp::e( - Tui::fg(Tui::g(0), "▐"), - Bsp::e(key, Tui::fg(Tui::g(96), "▐")) - )); - let label = When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label)); - Tui::bold(true, Bsp::e(key, label)) -} - -pub fn button_3 <'a, K, L, V> ( - key: K, - label: L, - value: V, - editing: bool, -) -> impl Content + 'a where - K: Content + 'a, - L: Content + 'a, - V: Content + 'a, -{ - let key = Tui::fg_bg(Tui::orange(), Tui::g(0), - Bsp::e(Tui::fg(Tui::g(0), "▐"), Bsp::e(key, Tui::fg(if editing { - Tui::g(128) - } else { - Tui::g(96) - }, "▐")))); - let label = Bsp::e( - When::new(!editing, Bsp::e( - Tui::fg_bg(Tui::g(255), Tui::g(96), label), - Tui::fg_bg(Tui::g(128), Tui::g(96), "▐"), - )), - Bsp::e( - Tui::fg_bg(Tui::g(224), Tui::g(128), value), - Tui::fg_bg(Tui::g(128), Reset, "▌"), - )); - Tui::bold(true, Bsp::e(key, label)) -} diff --git a/deps/tengri b/deps/tengri index 921378b6..f21781e8 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 921378b6dbb38d4f301f688abd1cfef9bdc0f941 +Subproject commit f21781e81664e1991e3985e2377becca9c1d58cf