improve cfg legibility and move more defs there

This commit is contained in:
i do not exist 2026-09-20 14:17:28 +03:00
parent 83c03f5a80
commit 8b96ddb411
8 changed files with 182 additions and 318 deletions

View file

@ -228,8 +228,9 @@ fn get_opt_usize <'a> (state: &App, src: impl Language) -> Perhaps<Option<usize>
fn get_axis <'a> (_: &App, src: impl Language) -> Perhaps<ControlAxis> { fn get_axis <'a> (_: &App, src: impl Language) -> Perhaps<ControlAxis> {
eval_word(src, |word|Ok(match word { eval_word(src, |word|Ok(match word {
":x" => ControlAxis::X, "X" => ControlAxis::X, "XFine" | "X2" => ControlAxis::XFine,
":y" => ControlAxis::Y, "Y" => ControlAxis::Y, "YFine" | "Y2" => ControlAxis::YFine,
"Z" => ControlAxis::Z, "ZFine" | "Z2" => ControlAxis::ZFine,
_ => return err!("unknown axis {word}") _ => return err!("unknown axis {word}")
@ -459,7 +460,10 @@ impl App {
/// let axis = tek::ControlAxis::X; /// let axis = tek::ControlAxis::X;
/// ``` /// ```
#[derive(Debug, Copy, Clone)] pub enum ControlAxis { #[derive(Debug, Copy, Clone)] pub enum ControlAxis {
X, Y, Z, I X, XFine,
Y, YFine,
Z, ZFine,
I, IFine,
} }
#[tek_proc::commands(AxisCommand)] #[tek_proc::commands(AxisCommand)]
@ -562,15 +566,21 @@ impl App {
} }
#[allow(unused)] fn draw_debug (&self, to: &mut Tui) -> Drawn<u16> { #[allow(unused)] fn draw_debug (&self, to: &mut Tui) -> Drawn<u16> {
east( Split::Above.bar(0,
format!("{}x{} ", Split::West.bar(16,
self.size.0.load(Relaxed), format!("{}/{} {} ",
self.size.1.load(Relaxed)), self.perf.used.load(Relaxed),
format!("{}/{} {} ", self.perf.window.load(Relaxed),
self.perf.used.load(Relaxed), self.perf.clock.raw() / 10000000).align_e(),
self.perf.window.load(Relaxed), format!("{}x{} ",
self.perf.clock.raw() / 10000000), self.size.0.load(Relaxed),
).align_se().draw(to) self.size.1.load(Relaxed)).align_w(),
).align_se(),
Split::East.bar(16,
format!("{}", self.modes.read()[0]),
format!("{}", self.modes.read()[0])
).align_sw()
).draw(to)
} }
} }

View file

@ -84,7 +84,8 @@ impl Action {
exit.clone(), exit.clone(),
{ {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut app = App::new(Some(exit), sesh.init()?, config, ":menu"); let mut app = App::new(Some(exit), sesh.init()?, config, "Menu");
app.dialog = Dialog::welcome();
#[cfg(feature = "prof2")] { #[cfg(feature = "prof2")] {
if trace { if trace {
app.guard = Some({ app.guard = Some({

View file

@ -449,23 +449,6 @@ impl_time_unit!(Pulse);
impl_time_unit!(Bpm); impl_time_unit!(Bpm);
impl_time_unit!(LaunchSync); impl_time_unit!(LaunchSync);
/// ```
/// let x = "";
/// let _ = tek::view_transport(true, x.as_ref(), x.as_ref(), x.as_ref());
/// let _ = tek::view_transport(false, x.as_ref(), x.as_ref(), x.as_ref());
/// ```
pub fn view_transport <'a> (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw<Tui> {
let theme = ItemTheme::G[96];
bg(Black, east!(above(
button_play_pause(play, false).align_w(),
east!(
field_h(theme, "BPM", bpm),
field_h(theme, "Beat", beat),
field_h(theme, "Time", time),
).align_e().full_wh()
)))
}
/// ``` /// ```
/// let x = ""; /// let x = "";
/// let _ = tek::view_status(None, x.as_ref(), x.as_ref(), x.as_ref()); /// let _ = tek::view_status(None, x.as_ref(), x.as_ref(), x.as_ref());

View file

@ -12,27 +12,11 @@ impl Binds {
let name = expr.head()?.ok_or("bind: missing name")?; let name = expr.head()?.ok_or("bind: missing name")?;
let body = expr.tail()?.unwrap_or(""); let body = expr.tail()?.unwrap_or("");
binds.0.try_write().unwrap().insert(name.into(), { binds.0.try_write().unwrap().insert(name.into(), {
let mut map = Bind::new(); let mut map: Bind<TuiEvent, Arc<str>> = Bind::new();
body.each((), |_, item: &str|if matches!(item.expr().head(), Ok(Some("see"))) { body.each((), |_, item: &str|if matches!(item.expr().head(), Ok(Some("see"))) {
// TODO Binds::add_ref(&mut map, item)
Ok(())
} else if let Ok(Some(_word)) = item.expr().head().word() { } else if let Ok(Some(_word)) = item.expr().head().word() {
let expr = item.expr()?; Binds::add_def(&mut map, item)
let head = expr.head()?;
if let Some(event) = TuiKey::from_dsl(&head)?.to_crossterm() {
map.add(TuiEvent(event), Binding {
commands: [item.expr()?.tail()?.unwrap_or_default().into()].into(),
condition: None,
description: None,
source: None
});
Ok(())
} else if Some(":char") == item.expr()?.head()? {
// TODO
return Ok(())
} else {
return err!("Binds::add: invalid key: {:?}", item.expr()?.head()?)
}
} else { } else {
return err!("Binds::add: unexpected: {item:?}") return err!("Binds::add: unexpected: {item:?}")
})?; })?;
@ -41,6 +25,30 @@ impl Binds {
Ok(()) Ok(())
} }
fn add_ref (_map: &mut Bind<TuiEvent, Arc<str>>, _item: &str) -> Usually<()> {
// TODO
Ok(())
}
fn add_def (map: &mut Bind<TuiEvent, Arc<str>>, item: &str) -> Usually<()> {
let expr = item.expr()?;
let head = expr.head()?;
if let Some(event) = TuiKey::from_dsl(&head)?.to_crossterm() {
map.add(TuiEvent(event), Binding {
commands: [item.expr()?.tail()?.unwrap_or_default().into()].into(),
condition: None,
description: None,
source: None
});
Ok(())
} else if Some(":char") == item.expr()?.head()? {
// TODO
Ok(())
} else {
err!("Binds::add: invalid key: {:?}", item.expr()?.head()?)
}
}
pub fn clear (&self) { pub fn clear (&self) {
*self.0.write() = Default::default(); *self.0.write() = Default::default();
} }

View file

@ -281,56 +281,55 @@ impl View<Tui, App> {
-> Usually<Arc<Box<dyn Fn(&App, &mut Tui)->Drawn<u16> + Send + Sync>>> -> Usually<Arc<Box<dyn Fn(&App, &mut Tui)->Drawn<u16> + Send + Sync>>>
{ {
macro_rules! draw { macro_rules! draw {
(|$state:ident|$body:expr)=>{Self::boxed(move|$state, to|$body.draw(to))} (|$state:ident|$body:expr)=>{Self::boxed(move|$state, to|$body.draw(to))};
($const:expr)=>{Self::boxed(move|_, to|$const.draw(to))};
()=>{Self::boxed(move|_, __|Ok(None))};
} }
Ok(Arc::new(match word.split("/").next() { Ok(Arc::new(match word.split("/").next() {
//Some(":logo") => view_logo().draw(to), Some("Beat") => draw!(),
Some(":meters") => match word.split("/").skip(1).next() { Some("Bpm") => draw!(),
Some("input") => Self::boxed(move|_, to|bg(Rgb(30, 30, 30), "Input Meters".align_s().full_h()).draw(to)), Some("BrowseTitle") => draw!(|app|view_browse_title(app)),
Some("output") => Self::boxed(move|_, to|bg(Rgb(30, 30, 30), "Output Meters".align_s().full_h()).draw(to)), Some("Debug") => Self::boxed(move|_, to|format!("[{:?}]", to.area()).exact_h(1).draw(to)),
_ => panic!() Some("Device") => draw!(|app|view_device(app)),
}, Some("Menu") => draw!(|app|{
Some(":tracks") => match &word[(":tracks".len()+1)..] { if let Dialog::Menu(selected, items) = &app.dialog {
"" => Self::boxed(move|_, to|"TODO tracks".draw(to)), Some(iter_south(move||items.iter().enumerate().map(move|(index, MenuItem(item, _))|{
let f = if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) };
"names" => draw!(|app|app.project.view_track_names(app.color.clone())), let b = if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) };
"names/count" => draw!(|app|app.project.view_track_names_count()), fg_bg(f, b, item).exact_h(2).align_x()
"names/cells" => draw!(|app|app.project.view_track_names_cells()), })).exact_w(20).align_x())
"names/add" => draw!(|app|app.project.view_track_names_add()), } else {
None
"devices" => draw!(|app|app.project.view_track_devices(app.color.clone())), }
"devices/count" => draw!(|app|app.project.view_track_device_count()), }),
"devices/cells" => draw!(|app|app.project.view_track_device_cells(app.tracks_devices_height())), Some("Editor") => draw!("TODO editor"),
"devices/add" => draw!(|app|app.project.view_track_device_add()), Some("MetersIn") => draw!(|___|bg(Rgb(30, 30, 30), "Input Meters".align_s().full_h())),
Some("MetersOut") => draw!(|___|bg(Rgb(30, 30, 30), "Output Meters".align_s().full_h())),
"inputs" => draw!(|app|app.project.view_track_inputs(app.color.clone())), Some("ModeList") => draw!(|app|app.modes.read().get(0)), // TODO all
"inputs/count" => draw!(|app|app.project.view_track_input_count()), Some("ScenesClips") => draw!(|app|app.view_scenes_clips()),
"inputs/cells" => draw!(|app|app.project.view_track_input_cells(app.tracks_inputs_height())), Some("ScenesNames") => draw!(|app|app.view_scenes_names()),
"inputs/add" => draw!(|app|app.project.view_track_input_add()), Some("Sessions") => draw!(|___|view_sessions()),
Some("Templates") => draw!(|app|view_templates(app)),
"outputs" => draw!(|app|app.project.view_track_outputs(app.color.clone(), 0)), Some("Time") => draw!(),
"outputs/count" => draw!(|app|app.project.view_track_output_count()), Some("Tracks") => draw!("TODO tracks"),
"outputs/cells" => draw!(|app|app.project.view_track_output_cells()), Some("TracksDevices") => draw!(|app|app.project.view_track_devices(app.color.clone())),
"outputs/add" => draw!(|app|app.project.view_track_output_add()), Some("TracksDevicesAdd") => draw!(|app|app.project.view_track_device_add()),
Some("TracksDevicesCells") => draw!(|app|app.project.view_track_device_cells(app.tracks_devices_height())),
_ => panic!("unknown: {word}") Some("TracksDevicesCount") => draw!(|app|app.project.view_track_device_count()),
}, Some("TracksInputs") => draw!(|app|app.project.view_track_inputs(app.color.clone())),
Some(":scenes") => match word.split("/").skip(1).next() { Some("TracksInputsAdd") => draw!(|app|app.project.view_track_input_add()),
Some("clips") => draw!(|app|app.view_scenes_clips()), Some("TracksInputsCells") => draw!(|app|app.project.view_track_input_cells(app.tracks_inputs_height())),
Some("names") => draw!(|app|app.view_scenes_names()), Some("TracksInputsCount") => draw!(|app|app.project.view_track_input_count()),
_ => panic!() Some("TracksNames") => draw!(|app|app.project.view_track_names(app.color.clone())),
}, Some("TracksNamesAdd") => draw!(|app|app.project.view_track_names_add()),
Some(":templates") => draw!(|app|view_templates(app)), Some("TracksNamesCells") => draw!(|app|app.project.view_track_names_cells()),
Some(":browse/title") => draw!(|app|view_browse_title(app)), Some("TracksNamesCount") => draw!(|app|app.project.view_track_names_count()),
Some(":device") => draw!(|app|view_device(app)), Some("TracksOutputs") => draw!(|app|app.project.view_track_outputs(app.color.clone(), 0)),
Some(":dialog") => Self::boxed(move|state, to|draw_dialog(to, word.split("/").skip(1), state)), Some("TracksOutputsAdd") => draw!(|app|app.project.view_track_output_add()),
Some(":sessions") => Self::boxed(move|_, to|view_sessions().draw(to)), Some("TracksOutputsCells") => draw!(|app|app.project.view_track_output_cells()),
Some(":status") => Self::boxed(move|state, to|draw_status_bar(to, state)), Some("TracksOutputsCount") => draw!(|app|app.project.view_track_output_count()),
Some(":editor") => Self::boxed(move|_, to|"TODO Editor".draw(to)), Some(_) => Self::boxed(move|state, to|if let Some(view) = state.config.get_view(word.as_ref()) {
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)),
Some(_) => Self::boxed(move|state, to|if let Some(view) = state.config.get_view(word.as_ref()) {
(view.render)(state, to) (view.render)(state, to)
} else { } else {
fg(Color::Rgb(128, 32, 32), format!("undefined: {word:?}")).draw(to) fg(Color::Rgb(128, 32, 32), format!("undefined: {word:?}")).draw(to)

View file

@ -55,25 +55,6 @@ pub fn get_dialog <'a> (_: &App, src: impl Language) -> Perhaps<Dialog> {
Options, Options,
} }
pub fn draw_dialog <'a, I: Debug + Iterator<Item = &'a str>> (to: &mut Tui, mut frags: I, state: &App)
-> Drawn<u16>
{
match frags.next() {
Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog {
Some(iter_south(move||items.iter().enumerate().map(move|(index, MenuItem(item, _))|{
let f = if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) };
let b = if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) };
fg_bg(f, b, item).exact_h(2).align_x()
})).exact_w(20).align_x())
} else {
None
}.draw(to),
_ => unimplemented!("draw_dialog: ({frags:?})"),
}
}
impl Dialog { impl Dialog {
/// ``` /// ```
@ -94,7 +75,7 @@ impl Dialog {
}, },
AppCommand::Mode { AppCommand::Mode {
command: ModeCommand::Reset { command: ModeCommand::Reset {
modes: vec![":arranger".into()] modes: vec!["Arranger".into()]
} }
}, },
AppCommand::Tracks { AppCommand::Tracks {

View file

@ -1,207 +1,86 @@
(view :logo (text tek )) (mode Menu (name Main Menu) (info Welcome to Tek!) (keys Y Confirm)
(view (bar/s 2 Transport (bar/n 2 Status (align/c (bar/s 2 (align/x (bg (g 12) Logo)) Menu))))))
(mode Transport (name Transport) (info JACK transport controller.)
(keys Clock Global)
(view Transport))
(mode Arranger (name Arranger) (info Launch grid.)
(keys Global Clock Tracks Scenes Clip Launch Color History)
(view (bar/n 2 Status (bar/s 8 (bar/e 16 (align/nw Transport)
(bar/w 20 (bar/s 2 (bar/w 4 TracksOutputsAdd TracksOutputsCount)
(bar/s 2 (bar/w 4 TracksDevicesAdd TracksDevicesCount)
(bar/s 2 (bar/w 4 TracksNamesAdd TracksNamesCount)
(bar/w 4 TracksInputsAdd TracksInputsCount))))
(align/x (bar/s 2 TracksOutputsCells
(bar/s 2 TracksDevicesCells
(bar/s 2 TracksNamesCells TracksInputsCells))))))
(bar/w 20 (text) (bar/e 16 ScenesNames ScenesClips))))))
(mode Sequencer (info MIDI sequencer.)
(keys Global Clock I IFine Y Page EditorView EditorAdd EditorDel)
(view (bsp/s (exact/h 1 Transport) (bsp/n (exact/h 1 Status) (fill/xy (bsp/a (fill/xy (align/e Pool)) Editor))))))
(mode Sampler (info Sample player.)
(keys SamplerDirs SamplerRec SamplerPlay)
(view (bsp/s (exact/h 1 Transport) (bsp/n (exact/h 1 Status) (fill/xy SampleGrid)))))
(mode Groovebox (info Sequencer with sampler.)
(keys Global Clock Sampler I IFine Y Page EditorView EditorAdd EditorDel)
(view (bsp/w MetersOut (bsp/e MetersIn (bsp/w GrooveMeta GrooveEditor)))))
(view :browse (bsp/s (view Logo (text tek! 0.4.0 ))
(pad/xy 3 1 :browse-title) (view Browse (bsp/s (pad/xy 3 1 BrowseTitle) (fg (g 96) browser)))
(fg (g 96) browser))) (view PortsOut (bsp/s (align/w (text L-AUDIO-OUT)) (bsp/e (text MIDI-OUT) (align/e (text AUDIO-OUT-R)))))
(view PortsIn (bsp/s (align/w (text L-AUDIO-IN)) (bsp/e (text MIDI-IN) (align/e (text AUDIO-IN-R)))))
(view GrooveMeta (fill/y (align/n (stack/s Pool MidiInsStatus MidiOutsStatus AudioInsStatus AudioOutsStatus))))
(view GrooveEditor (bsp/n GrooveSample GrooveSequence))
(view GrooveSample (exact/h SampleHeight (bsp/e (fill/y (exact/w 20 (align/nw SampleStatus))) SampleViewer)))
(view GrooveSequence (bsp/e (fill/y (align/n (bsp/s Status/v EditorStatus))) (bsp/e SamplesKeys Editor)))
(view Status (bar/s 1 (text Mode) ModeList))
(view Transport (bg (g 0) (pad/x 1 (bar/e 4 PlayPause (bar/e 16 Bpm (bar/e 16 Beat Time))))))
(mode :transport (keys Global (@f1 (dialog Help))
(name Transport) (@f2 (project new))
(info JACK transport controller.) (@f3 (dialog History))
(keys :clock :global) (@f6 (dialog :save))
:transport) (@f8 (dialog :options))
(@f9 (dialog :load))
(@f10 (dialog :quit)))
(mode :menu (keys Back (@escape cancel))
(name Menu) (keys Confirm (@enter confirm))
(info Mode selector.) (keys Page (@pgup page/up) (@pgdn page/down))
(keys :axis/y :confirm) (keys Delete (@delete delete) (@backspace delete/back))
(view (keys History (@u (undo 1)) (@r (redo 1)))
(bar/s 2 (pad/x 1 :transport) (keys X (@left (axis (dec X))) (@right (axis (inc X))))
(bar/n 2 :status (keys Y (@up (axis (dec Y))) (@down (axis (inc Y))))
(align/c (keys Z (@minus (axis (dec Z))) (@equal (axis (inc Z))))
(bar/s 2 (align/x (bg (g 12) :logo)) (keys I (@comma (axis (dec I))) (@period (axis (inc Z))))
:dialog/menu)))))) (keys W (@openbracket (axis (dec W))) (@closebracket (axis (inc W))))
(keys XFine (@shift/left (axis (dec XFine))) (@shift/right (axis (inc XFine))))
(keys YFine (@shift/up (axis (dec YFine))) (@shift/down (axis (inc YFine))))
(keys ZFine (@underscore (axis (dec ZFine))) (@plus (axis (inc ZFine))))
(keys IFine (@lt (axis (dec IFine))) (@gt (axis (inc ZFine))))
(keys WFine (@openbrace (axis (dec WFine))) (@closebrace (axis (inc WFine))))
(keys :back (@escape cancel)) (keys Clock (@space (clock/toggle 0)) (@shift/space (clock/toggle 0)))
(keys :confirm (@enter confirm)) (keys Scenes (@shift/S (scenes add)) (@s (scenes select)) (@up (scenes prev)) (@down (scenes next)))
(keys :axis/y (@up (axis (dec :y))) (keys Tracks (@shift/T (tracks add)) (@t (tracks select)) (@left (tracks prev)) (@right (tracks next)))
(@down (axis (inc :y)))) (keys Clip (@l (toggle :loop)) (@tab (clip upsert) (edit toggle)))
(keys Color (@c (color)))
(keys Launch (@q (launch)))
(mode :arranger (name Arranger) (info Launch grid.) (keys EditorView (see X XFine Z ZFine) (@z toggle :lock))
(keys :clock :color :launch :scenes :tracks :clip :global :history :saveload) (keys EditorAdd (@a editor/append :true) (@enter editor/append :false))
(mode :editor (keys :editor)) (keys EditorDel (@del editor/delete/note) (@shift/del editor/delete/note))
(mode :dialog (keys :dialog))
(mode :message (keys :message))
(mode :add-device (keys :add-device))
(mode :browse (keys :browse))
(mode :rename (keys :input))
(mode :length (keys :rename))
(mode :clip (keys :clip))
(mode :track (keys :track))
(mode :scene (keys :scene))
(mode :mix (keys :mix))
(view
(bar/n 2 :status
(bar/s 8
(bar/e 16 (align/nw (pad/x 1 :transport))
(bar/w 20 (bar/s 2 (bar/w 4 :tracks/outputs/add :tracks/outputs/count)
(bar/s 2 (bar/w 4 :tracks/devices/add :tracks/devices/count)
(bar/s 2 (bar/w 4 :tracks/names/add :tracks/names/count)
(bar/w 4 :tracks/inputs/add :tracks/inputs/count))))
(align/x
(bar/s 2 :tracks/outputs/cells
(bar/s 2 :tracks/devices/cells
(bar/s 2 :tracks/names/cells
:tracks/inputs/cells))))))
(bar/w 20 (text)
(bar/e 16 :scenes/names
:scenes/clips))))))
(keys :global (keys Sequencer (see Color Launch) (@shift/I input/add) (@shift/O output/add))
(@f1 (dialog :help))
(@f2 (project new))
(@f3 (dialog :history))
(@f6 (dialog :save))
(@f8 (dialog :options))
(@f9 (dialog :load))
(@f10 (dialog :quit)))
(keys :clock (keys SamplerRec (@r sampler/record/toggle SelectedSample) (@shift/R sampler/record/back))
(@space (clock/toggle 0)) (keys SamplerPlay (@p sampler/play/sample SelectedSample) (@P sampler/stop/sample SelectedSample))
(@shift/space (clock/toggle 0))) (keys SamplerImpEx (@shift/f6 dialog :export/sample) (@shift/f9 dialog Import/sample))
(keys SamplerDirs (@up sampler/select :sample/above) (@down sampler/select :sample/below) (@left sampler/select :sample/to/left) (@right sampler/select :sample/to/right))
(keys :color (keys Track (see Color Launch Z ZFine Delete) (@r toggle :rec) (@m toggle :mon) (@p toggle :play) (@P toggle :solo))
(@c (color))) (keys Scene (see Color Launch Z ZFine Delete))
(keys Input (see X Delete) (:char input))
(keys :launch (keys List (see Y Confirm))
(@q (launch))) (keys Length (see X Y Confirm))
(keys Browse (see List Input))
(keys :scenes (keys Pool (see Y W ZFine Color Delete) (@n rename/begin) (@t length/begin) (@m import/begin) (@x export/begin) (@shift/A clip/add :after :newClip) (@shift/D clip/add :after :clonedClip))
(@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))
(@tab (clip upsert) (edit toggle)))
(view :ports/out
(bsp/s (align/w (text L-AUDIO-OUT))
(bsp/e (text MIDI-OUT)
(align/e (text AUDIO-OUT-R)))))
(view :ports/in
(bsp/s (align/w (text L-AUDIO-IN))
(bsp/e (text MIDI-IN)
(align/e (text AUDIO-IN-R)))))
(mode :sequencer (name Sequencer) (info MIDI sequencer.)
(keys :editor :clock :global)
(mode browse (keys :browse))
(mode rename (keys :pool/rename))
(mode length (keys :pool/length))
(view
(bsp/s (exact/h 1 :transport)
(bsp/n (exact/h 1 :status)
(fill/xy (bsp/a (fill/xy (align/e :pool))
:editor))))))
(mode :sampler (name Sampler) (info Sample player.)
(keys :sampler/directions :sampler/record :sampler/play)
(view
(bsp/s (exact/h 1 :transport)
(bsp/n (exact/h 1 :status)
(fill/xy :samples/grid)))))
(mode :groovebox (name Groovebox) (info Sequencer with sampler.)
(keys :clock :editor :sampler :global)
(mode browse (keys :browse))
(mode rename (keys :pool-rename))
(mode length (keys :pool-length))
(view
(bsp/w :meters/output
(bsp/e :meters/input
(bsp/w :groove/meta
:groove/editor)))))
(view :groove/meta (fill/y (align/n (stack/s :midi-ins/status :midi-outs/status :audio-ins/status :audio-outs/status :pool))))
(view :groove/editor (bsp/n :groove/sample :groove/sequence))
(view :groove/sample (exact/h :h-sample-detail (bsp/e (fill/y (exact/w 20 (align/nw :sample-status))) :sample-viewer)))
(view :groove/sequence (bsp/e (fill/y (align/n (bsp/s :status/v :editor-status))) (bsp/e :samples/keys :editor)))
(keys :axis/x (@left dec :x)
(@right inc :x))
(keys :axis/x2 (@shift/left dec :x2)
(@shift/right inc :x2))
(keys :axis/y2 (@shift/up dec :y2)
(@shift/down inc :y2))
(keys :axis/z (@minus dec :z)
(@equal inc :z))
(keys :axis/z2 (@underscore dec :z2)
(@plus inc :z2))
(keys :axis/i (@comma dec :i)
(@period inc :z))
(keys :axis/i2 (@lt dec :i2)
(@gt inc :z2))
(keys :axis/w (@openbracket dec :w)
(@closebracket inc :w))
(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)
(@z toggle :lock))
(keys :editor/add (@a editor/append :true)
(@enter editor/append :false))
(keys :editor/del (@del editor/delete/note)
(@shift/del editor/delete/note))
(keys :sampler/record (@r sampler/record/toggle :sample/selected)
(@shift/R sampler/record/back))
(keys :sampler/play (@p sampler/play/sample :sample/selected)
(@P sampler/stop/sample :sample/selected))
(keys :sampler/import-export (@shift/f6 dialog :export/sample)
(@shift/f9 dialog :import/sample))
(keys :sampler/directions (@up sampler/select :sample/above)
(@down sampler/select :sample/below)
(@left sampler/select :sample/to/left)
(@right sampler/select :sample/to/right))
(keys :track (see :color :launch :axis/z :axis/z2 :delete)
(@r toggle :rec)
(@m toggle :mon)
(@p toggle :play)
(@P toggle :solo))
(keys :scene (see :color :launch :axis/z :axis/z2 :delete))
(keys :help (@f1 dialog :help))
(keys :page (@pgup page/up)
(@pgdn page/down))
(keys :delete (@delete delete)
(@backspace delete/back))
(keys :input (see :axis/x :delete) (:char input))
(keys :list (see :axis/y :confirm))
(keys :length (see :axis/x :axis/y :confirm))
(keys :browse (see :list :input :focus))
(keys :history (@u undo 1)
(@r redo 1))
(keys :saveload (@f6 dialog :save)
(@f9 dialog :load))
(keys :sequencer (see :color :launch)
(@shift/I input/add)
(@shift/O output/add))
(keys :pool (see :axis-y :axis-w :axis/z2 :color :delete)
(@n rename/begin)
(@t length/begin)
(@m import/begin)
(@x export/begin)
(@shift/A clip/add :after :new/clip)
(@shift/D clip/add :after :cloned/clip))

View file

@ -78,13 +78,13 @@ fn main () -> Usually<()> {
fn run_new_plain (config: Config) -> Usually<()> { fn run_new_plain (config: Config) -> Usually<()> {
let name = "tek"; let name = "tek";
tengri::Tui::run_main(Jack::new_run(name, move|jack|{ tengri::Tui::run_main(Jack::new_run(name, move|jack|{
let mode = ":menu"; let mode = "Menu";
let title = "untitled!"; let title = "untitled!";
let bpm = 74.; let bpm = 74.;
let clock = Clock::new(&jack, Some(bpm))?; let clock = Clock::new(&jack, Some(bpm))?;
let tracks = []; let tracks = [];
let scenes = []; let scenes = [];
Ok(App::new(None, Project::new( let project = Project::new(
&jack, &jack,
title.into(), title.into(),
clock, clock,
@ -96,6 +96,9 @@ fn run_new_plain (config: Config) -> Usually<()> {
.chain(connect_audio_ins(&jack, &"R", &[], None)?.into_iter()), .chain(connect_audio_ins(&jack, &"R", &[], None)?.into_iter()),
[].into_iter().chain(connect_audio_outs(&jack, &"L", &[], None)?.into_iter()) [].into_iter().chain(connect_audio_outs(&jack, &"L", &[], None)?.into_iter())
.chain(connect_audio_outs(&jack, &"R", &[], None)?.into_iter()), .chain(connect_audio_outs(&jack, &"R", &[], None)?.into_iter()),
), config, mode)) );
let mut app = App::new(None, project, config, mode);
app.dialog = Dialog::welcome();
Ok(app)
})?) })?)
} }