wip: namespaces

This commit is contained in:
🪞👃🪞 2025-08-10 02:36:48 +03:00
parent 525a455f7a
commit f2d6e7724b
4 changed files with 174 additions and 169 deletions

View file

@ -1,93 +1,87 @@
use crate::*;
//handle!(TuiIn:|self: App, input|self.
impl App {
fn handle_tui_key_with_history (&mut self, input: &TuiIn) -> Perhaps<bool> {
panic!("{input:?}");
//Ok(if let Some(binding) = self.profile.as_ref()
//.map(|c|c.keys.dispatch(input.event())).flatten()
//{
//let binding = binding.clone();
//let undo = binding.command.clone().execute(self)?;
//// FIXME failed commands are not persisted in undo history
////self.history.push((binding.command.clone(), undo));
//Some(true)
//} else {
//None
//})
}
}
type MaybeClip = Option<Arc<RwLock<MidiClip>>>;
macro_rules!dsl_expose(($Struct:ident { $($fn:ident: $ret:ty = |$self:ident|$body:expr);* $(;)? })=>{
#[tengri_proc::expose] impl $Struct { $(fn $fn (&$self) -> $ret { $body })* }
handle!(TuiIn:|self: App, input|{
panic!("{input:?}");
//Ok(if let Some(binding) = self.profile.as_ref()
//.map(|c|c.keys.dispatch(input.event())).flatten()
//{
//let binding = binding.clone();
//let undo = binding.command.clone().execute(self)?;
//// FIXME failed commands are not persisted in undo history
////self.history.push((binding.command.clone(), undo));
//Some(true)
//} else {
//None
//})
})
dsl_sym!(|app: App| -> isize {
":_isize_stub" => -1
});
dsl_expose!(App {
_isize_stub: isize = |self|todo!();
_item_theme_stub: ItemTheme = |self|todo!();
w_sidebar: u16 = |self|self.project.w_sidebar(self.editor().is_some());
h_sample_detail: u16 = |self|6.max(self.height() as u16 * 3 / 9);
focus_editor: bool = |self|self.project.editor.is_some();
focus_dialog: bool = |self|!matches!(self.dialog, Dialog::None);
focus_message: bool = |self|matches!(self.dialog, Dialog::Message(..));
focus_add_device: bool = |self|matches!(self.dialog, Dialog::Device(..));
focus_browser: bool = |self|self.dialog.browser().is_some();
focus_clip: bool = |self|!self.focus_editor() && matches!(self.selection(), Selection::TrackClip{..});
focus_track: bool = |self|!self.focus_editor() && matches!(self.selection(), Selection::Track(..));
focus_scene: bool = |self|!self.focus_editor() && matches!(self.selection(), Selection::Scene(..));
focus_mix: bool = |self|!self.focus_editor() && matches!(self.selection(), Selection::Mix);
focus_pool_import: bool = |self|matches!(self.pool.mode, Some(PoolMode::Import(..)));
focus_pool_export: bool = |self|matches!(self.pool.mode, Some(PoolMode::Export(..)));
focus_pool_rename: bool = |self|matches!(self.pool.mode, Some(PoolMode::Rename(..)));
focus_pool_length: bool = |self|matches!(self.pool.mode, Some(PoolMode::Length(..)));
dialog_none: Option<Dialog> = |self|None;
dialog_device: Option<Dialog> = |self|Some(Dialog::Device(0)); // TODO
dialog_device_prev: Option<Dialog> = |self|Some(Dialog::Device(0)); // TODO
dialog_device_next: Option<Dialog> = |self|Some(Dialog::Device(0)); // TODO
dialog_help: Option<Dialog> = |self|Some(Dialog::Help(0));
dialog_menu: Option<Dialog> = |self|Some(Dialog::Menu(0));
dialog_save: Option<Dialog> = |self|Some(Dialog::Browser(BrowserTarget::SaveProject, Browser::new(None).unwrap().into()));
dialog_load: Option<Dialog> = |self|Some(Dialog::Browser(BrowserTarget::LoadProject, Browser::new(None).unwrap().into()));
dialog_import_clip: Option<Dialog> = |self|Some(Dialog::Browser(BrowserTarget::ImportClip(Default::default()), Browser::new(None).unwrap().into()));
dialog_export_clip: Option<Dialog> = |self|Some(Dialog::Browser(BrowserTarget::ExportClip(Default::default()), Browser::new(None).unwrap().into()));
dialog_import_sample: Option<Dialog> = |self|Some(Dialog::Browser(BrowserTarget::ImportSample(Default::default()), Browser::new(None).unwrap().into()));
dialog_export_sample: Option<Dialog> = |self|Some(Dialog::Browser(BrowserTarget::ExportSample(Default::default()), Browser::new(None).unwrap().into()));
dialog_options: Option<Dialog> = |self|Some(Dialog::Options);
editor_pitch: Option<u7> = |self|Some((self.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8).into());
scene_count: usize = |self|self.scenes().len();
scene_selected: Option<usize> = |self|self.selection().scene();
track_count: usize = |self|self.tracks().len();
track_selected: Option<usize> = |self|self.selection().track();
select_scene: Selection = |self|self.selection().select_scene(self.tracks().len());
select_scene_next: Selection = |self|self.selection().select_scene_next(self.scenes().len());
select_scene_prev: Selection = |self|self.selection().select_scene_prev();
select_track: Selection = |self|self.selection().select_track(self.tracks().len());
select_track_next: Selection = |self|self.selection().select_track_next(self.tracks().len());
select_track_prev: Selection = |self|self.selection().select_track_prev();
clip_selected: Option<Arc<RwLock<MidiClip>>> = |self|match self.selection() {
Selection::TrackClip { track, scene } => self.scenes()[*scene].clips[*track].clone(),
_ => None };
device_kind: usize = |self|if let Dialog::Device(index) = self.dialog {
index } else { 0 };
device_kind_next: usize = |self|if let Dialog::Device(index) = self.dialog {
(index + 1) % device_kinds().len() } else { 0 };
device_kind_prev: usize = |self|if let Dialog::Device(index) = self.dialog {
index.overflowing_sub(1).0.min(device_kinds().len().saturating_sub(1))
} else { 0 };
dsl_sym!(|app: App| -> ItemTheme {
":_theme_stub" => Default::default()
});
macro_rules!dsl_bind(($Command:ident: $State:ident {
$($fn:ident = |$state:ident $(, $arg:ident:$ty:ty)*|$body:expr);* $(;)?
})=>{
handle!(TuiIn: |self: $State, input|self.handle_tui_key_with_history(input));
#[tengri_proc::command(App)] impl $Command {
$(fn $fn ($state: &mut $State $(, $arg:$ty)*) -> Perhaps<Self> { $body })*
dsl_sym!(|app: App| -> u16{
":w/sidebar" => app.project.w_sidebar(app.editor().is_some()),
":h/sample-detail" => 6.max(app.height() as u16 * 3 / 9),
});
dsl_sym!(|app: App| -> usize {
":scene-count" => app.scenes().len(),
":track-count" => app.tracks().len(),
":device-kind" => app.dialog.device_kind().unwrap_or(0),
":device-kind/next" => app.dialog.device_kind_next().unwrap_or(0),
":device-kind/prev" => app.dialog.device_kind_prev().unwrap_or(0),
});
dsl_sym!(|app: App| -> bool {
":focused/editor" => app.project.editor.is_some(),
":focused/dialog" => !matches!(app.dialog, Dialog::None),
":focused/message" => matches!(app.dialog, Dialog::Message(..)),
":focused/add_device" => matches!(app.dialog, Dialog::Device(..)),
":focused/browser" => app.dialog.browser().is_some(),
":focused/clip" => !app.focused_editor() && matches!(app.selection(), Selection::TrackClip{..}),
":focused/track" => !app.focused_editor() && matches!(app.selection(), Selection::Track(..)),
":focused/scene" => !app.focused_editor() && matches!(app.selection(), Selection::Scene(..)),
":focused/mix" => !app.focused_editor() && matches!(app.selection(), Selection::Mix),
":focused/pool/import" => matches!(app.pool.mode, Some(PoolMode::Import(..))),
":focused/pool/export" => matches!(app.pool.mode, Some(PoolMode::Export(..))),
":focused/pool/rename" => matches!(app.pool.mode, Some(PoolMode::Rename(..))),
":focused/pool/length" => matches!(app.pool.mode, Some(PoolMode::Length(..))),
});
dsl_sym!(|app: App| -> Dialog {
":dialog/none" => Dialog::None,
":dialog/options" => Dialog::Options,
":dialog/device" => Dialog::Device(0),
":dialog/device/prev" => Dialog::Device(0),
":dialog/device/next" => Dialog::Device(0),
":dialog/help" => Dialog::Help(0),
":dialog/menu" => Dialog::Menu(0),
":dialog/save" => Dialog::Browser(BrowserTarget::SaveProject, Browser::new(None).unwrap().into()),
":dialog/load" => Dialog::Browser(BrowserTarget::LoadProject, Browser::new(None).unwrap().into()),
":dialog/import/clip" => Dialog::Browser(BrowserTarget::ImportClip(Default::default()), Browser::new(None).unwrap().into()),
":dialog/export/clip" => Dialog::Browser(BrowserTarget::ExportClip(Default::default()), Browser::new(None).unwrap().into()),
":dialog/import/sample" => Dialog::Browser(BrowserTarget::ImportSample(Default::default()), Browser::new(None).unwrap().into()),
":dialog/export/sample" => Dialog::Browser(BrowserTarget::ExportSample(Default::default()), Browser::new(None).unwrap().into()),
});
dsl_sym!(|app: App| -> Selection {
":select/scene" => app.selection().select_scene(app.tracks().len()),
":select/scene/next" => app.selection().select_scene_next(app.scenes().len()),
":select/scene/prev" => app.selection().select_scene_prev(),
":select/track" => app.selection().select_track(app.tracks().len()),
":select/track/next" => app.selection().select_track_next(app.tracks().len()),
":select/track/prev" => app.selection().select_track_prev(),
});
dsl_sym!(|app: App| -> Option<u7> {
":editor/pitch" => Some((app.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8).into())
})
dsl_sym!(|app: App| -> Option<usize> {
":selected/scene" => app.selection().scene(),
":selected/track" => app.selection().track(),
});
dsl_sym!(|app: App| -> Option<Arc<RwLock<MidiClip>>> {
":selected/clip" => if let Selection::TrackClip { track, scene } = app.selection() {
app.scenes()[*scene].clips[*track].clone(),
} else {
None
}
});
dsl_bind!(AppCommand: App {
enqueue = |app, clip: Option<Arc<RwLock<MidiClip>>>| { todo!() };
history = |app, delta: isize| { todo!() };