This commit is contained in:
🪞👃🪞 2025-05-14 17:59:06 +03:00
parent d7bbc2a412
commit e3a3962130
15 changed files with 74 additions and 81 deletions

View file

@ -1,9 +1,9 @@
(@esc cancel-dialog) (@esc dialog :dialog-none)
(@f1 toggle-dialog :dialog-help) (@f1 dialog :dialog-help)
(@f6 toggle-dialog :dialog-save) (@f6 dialog :dialog-save)
(@f8 toggle-dialog :dialog-options) (@f8 dialog :dialog-options)
(@f9 toggle-dialog :dialog-load) (@f9 dialog :dialog-load)
(@f10 toggle-dialog :dialog-quit) (@f10 dialog :dialog-quit)
(@u undo 1) (@u undo 1)
(@r redo 1) (@r redo 1)

View file

@ -18,8 +18,8 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
})); }));
#[tengri_proc::command(App)] impl AppCommand { #[tengri_proc::command(App)] impl AppCommand {
fn toggle_dialog (app: &mut App, dialog: Dialog) -> Perhaps<Self> { fn dialog (app: &mut App, dialog: Option<Dialog>) -> Perhaps<Self> {
app.toggle_dialog(Some(dialog)); app.toggle_dialog(dialog);
Ok(None) Ok(None)
} }
fn cancel_dialog (app: &mut App) -> Perhaps<Self> { fn cancel_dialog (app: &mut App) -> Perhaps<Self> {

View file

@ -16,12 +16,9 @@
#![feature(type_changing_struct_update)] #![feature(type_changing_struct_update)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(closure_lifetime_binder)] #![feature(closure_lifetime_binder)]
/// Standard result type.
pub type Usually<T> = std::result::Result<T, Box<dyn std::error::Error>>;
/// Standard optional result type.
pub type Perhaps<T> = std::result::Result<Option<T>, Box<dyn std::error::Error>>;
pub use ::tek_engine:: *; pub use ::tek_engine:: *;
pub use ::tek_device::{self, *}; pub use ::tek_device::{self, *};
pub use ::tengri::{Usually, Perhaps, Has};
pub use ::tengri::dsl::*; pub use ::tengri::dsl::*;
pub use ::tengri::input::*; pub use ::tengri::input::*;
pub use ::tengri::output::*; pub use ::tengri::output::*;

View file

@ -35,8 +35,8 @@ has!(Vec<JackMidiIn>: |self: App|self.project.midi_ins);
has!(Vec<JackMidiOut>: |self: App|self.project.midi_outs); has!(Vec<JackMidiOut>: |self: App|self.project.midi_outs);
has!(Vec<Scene>: |self: App|self.project.scenes); has!(Vec<Scene>: |self: App|self.project.scenes);
has!(Vec<Track>: |self: App|self.project.tracks); has!(Vec<Track>: |self: App|self.project.tracks);
has!(Measure<TuiOut>: |self: App|self.size);
has_size!(<TuiOut>|self: App|&self.size);
has_clips!(|self: App|self.project.pool.clips); has_clips!(|self: App|self.project.pool.clips);
has_editor!(|self: App|{ has_editor!(|self: App|{
editor = self.editor; editor = self.editor;
@ -152,8 +152,8 @@ impl App {
/// Various possible dialog overlays /// Various possible dialog overlays
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Dialog { pub enum Dialog {
Help, Help(usize),
Menu, Menu(usize),
Device(usize), Device(usize),
Message(Message), Message(Message),
Save(Browser), Save(Browser),
@ -216,29 +216,32 @@ impl App {
fn focus_pool_length (&self) -> bool { fn focus_pool_length (&self) -> bool {
matches!(self.project.pool.mode, Some(PoolMode::Length(..))) matches!(self.project.pool.mode, Some(PoolMode::Length(..)))
} }
fn dialog_device (&self) -> Dialog { fn dialog_none (&self) -> Option<Dialog> {
Dialog::Device(0) // TODO None
} }
fn dialog_device_prev (&self) -> Dialog { fn dialog_device (&self) -> Option<Dialog> {
Dialog::Device(0) // TODO Some(Dialog::Device(0)) // TODO
} }
fn dialog_device_next (&self) -> Dialog { fn dialog_device_prev (&self) -> Option<Dialog> {
Dialog::Device(0) // TODO Some(Dialog::Device(0)) // TODO
} }
fn dialog_help (&self) -> Dialog { fn dialog_device_next (&self) -> Option<Dialog> {
Dialog::Help Some(Dialog::Device(0)) // TODO
} }
fn dialog_menu (&self) -> Dialog { fn dialog_help (&self) -> Option<Dialog> {
Dialog::Menu Some(Dialog::Help(0))
} }
fn dialog_save (&self) -> Dialog { fn dialog_menu (&self) -> Option<Dialog> {
Dialog::Save(Default::default()) Some(Dialog::Menu(0))
} }
fn dialog_load (&self) -> Dialog { fn dialog_save (&self) -> Option<Dialog> {
Dialog::Load(Default::default()) Some(Dialog::Save(Default::default()))
} }
fn dialog_options (&self) -> Dialog { fn dialog_load (&self) -> Option<Dialog> {
Dialog::Options Some(Dialog::Load(Default::default()))
}
fn dialog_options (&self) -> Option<Dialog> {
Some(Dialog::Options)
} }
fn editor_pitch (&self) -> Option<u7> { fn editor_pitch (&self) -> Option<u7> {
Some((self.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8).into()) Some((self.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8).into())

View file

@ -58,10 +58,10 @@ impl App {
Fixed::xy(70, 23, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b( Fixed::xy(70, 23, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b(
Repeat(" "), Outer(true, Style::default().fg(Tui::g(96))) Repeat(" "), Outer(true, Style::default().fg(Tui::g(96)))
.enclose(self.dialog.as_ref().map(|dialog|match dialog { .enclose(self.dialog.as_ref().map(|dialog|match dialog {
Dialog::Menu => Dialog::Menu(_) =>
self.view_dialog_menu().boxed(), self.view_dialog_menu().boxed(),
Dialog::Help => Dialog::Help(offset) =>
self.view_dialog_help().boxed(), self.view_dialog_help(*offset).boxed(),
Dialog::Save(browser) => Dialog::Save(browser) =>
self.view_dialog_save().boxed(), self.view_dialog_save().boxed(),
Dialog::Load(browser) => Dialog::Load(browser) =>
@ -84,12 +84,13 @@ impl App {
let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a)); let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a));
Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option))) Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option)))
} }
pub fn view_dialog_help <'a> (&'a self) -> impl Content<TuiOut> + use<'a> { pub fn view_dialog_help <'a> (&'a self, offset: usize) -> impl Content<TuiOut> + use<'a> {
Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1,
||self.config.keys.layers.iter() move||self.config.keys.layers.iter()
.filter_map(|a|(a.0)(self).then_some(a.1)) .filter_map(|a|(a.0)(self).then_some(a.1))
.flat_map(|a|a) .flat_map(|a|a)
.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None }) .filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None })
.skip(offset)
.take(20), .take(20),
|mut b,i|Fixed::x(60, Align::w(Bsp::e("(", Bsp::e( |mut b,i|Fixed::x(60, Align::w(Bsp::e("(", Bsp::e(
b.next().map(|t|Fixed::x(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))), b.next().map(|t|Fixed::x(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))),

View file

@ -46,6 +46,7 @@ has!(Vec<JackMidiIn>: |self: Arrangement|self.midi_ins);
has!(Vec<JackMidiOut>: |self: Arrangement|self.midi_outs); has!(Vec<JackMidiOut>: |self: Arrangement|self.midi_outs);
has!(Vec<Scene>: |self: Arrangement|self.scenes); has!(Vec<Scene>: |self: Arrangement|self.scenes);
has!(Vec<Track>: |self: Arrangement|self.tracks); has!(Vec<Track>: |self: Arrangement|self.tracks);
has!(Measure<TuiOut>: |self: Arrangement|self.size);
impl Arrangement { impl Arrangement {
/// Width of display /// Width of display

View file

@ -18,7 +18,7 @@ impl<'a> ArrangerView<'a> {
pub(crate) fn input_ports (&'a self) -> impl Content<TuiOut> + 'a { pub(crate) fn input_ports (&'a self) -> impl Content<TuiOut> + 'a {
Tryptich::top(1) Tryptich::top(1)
.left(self.width_side, .left(self.width_side,
button_3("i", "midi ins", format!("{}", self.inputs_count), self.is_editing)) button_3("i", "midi ins", format!("{}", self.arrangement.midi_ins().len()), self.is_editing))
.right(self.width_side, .right(self.width_side,
button_2("I", "add midi in", self.is_editing)) button_2("I", "add midi in", self.is_editing))
.middle(self.width_mid, .middle(self.width_mid,
@ -96,7 +96,12 @@ impl<'a> ArrangerView<'a> {
} }
pub(crate) fn output_count (&'a self) -> impl Content<TuiOut> + 'a { pub(crate) fn output_count (&'a self) -> impl Content<TuiOut> + 'a {
button_3("o", "midi outs", format!("{}", self.outputs_count), self.is_editing) button_3(
"o",
"midi outs",
format!("{}", self.arrangement.midi_outs().len()),
self.is_editing
)
} }
pub(crate) fn output_add (&'a self) -> impl Content<TuiOut> + 'a { pub(crate) fn output_add (&'a self) -> impl Content<TuiOut> + 'a {

View file

@ -9,20 +9,15 @@ pub struct ArrangerView<'a> {
pub width_mid: u16, pub width_mid: u16,
pub width_side: u16, pub width_side: u16,
pub inputs_count: usize,
pub inputs_height: u16, pub inputs_height: u16,
pub outputs_count: usize,
pub outputs_height: u16, pub outputs_height: u16,
pub scene_last: usize, pub scene_last: usize,
pub scene_count: usize,
pub scene_scroll: Fill<Fixed<u16, ScrollbarV>>, pub scene_scroll: Fill<Fixed<u16, ScrollbarV>>,
pub scene_selected: Option<usize>, pub scene_selected: Option<usize>,
pub scenes_height: u16, pub scenes_height: u16,
pub track_scroll: Fill<Fixed<u16, ScrollbarH>>, pub track_scroll: Fill<Fixed<u16, ScrollbarH>>,
pub track_count: usize,
pub track_selected: Option<usize>, pub track_selected: Option<usize>,
pub tracks_height: u16, pub tracks_height: u16,
@ -47,14 +42,10 @@ impl<'a> ArrangerView<'a> {
width_side: arrangement.w_sidebar(is_editing), width_side: arrangement.w_sidebar(is_editing),
inputs_height: arrangement.h_inputs(), inputs_height: arrangement.h_inputs(),
inputs_count: arrangement.midi_ins.len(),
outputs_height: arrangement.h_outputs(), outputs_height: arrangement.h_outputs(),
outputs_count: arrangement.midi_outs.len(),
scenes_height: h_scenes_area, scenes_height: h_scenes_area,
scene_selected: arrangement.selection().scene(), scene_selected: arrangement.selection().scene(),
scene_count: arrangement.scenes.len(),
scene_last: arrangement.scenes.len().saturating_sub(1), scene_last: arrangement.scenes.len().saturating_sub(1),
scene_scroll: Fill::y(Fixed::x(1, ScrollbarV { scene_scroll: Fill::y(Fixed::x(1, ScrollbarV {
offset: arrangement.scene_scroll, offset: arrangement.scene_scroll,
@ -63,7 +54,6 @@ impl<'a> ArrangerView<'a> {
})), })),
tracks_height: h_tracks_area, tracks_height: h_tracks_area,
track_count: arrangement.tracks.len(),
track_selected: arrangement.selection().track(), track_selected: arrangement.selection().track(),
track_scroll: Fill::x(Fixed::y(1, ScrollbarH { track_scroll: Fill::x(Fixed::y(1, ScrollbarH {
offset: arrangement.track_scroll, offset: arrangement.track_scroll,
@ -108,9 +98,9 @@ impl<'a> ArrangerView<'a> {
/// Render track headers /// Render track headers
pub(crate) fn tracks (&'a self) -> impl Content<TuiOut> + 'a { pub(crate) fn tracks (&'a self) -> impl Content<TuiOut> + 'a {
let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self; let Self { width_side, width_mid, track_selected, is_editing, .. } = self;
Tryptich::center(3) Tryptich::center(3)
.left(*width_side, button_3("t", "track", format!("{}", *track_count), *is_editing)) .left(*width_side, button_3("t", "track", format!("{}", self.arrangement.tracks.len()), *is_editing))
.right(*width_side, button_2("T", "add track", *is_editing)) .right(*width_side, button_2("T", "add track", *is_editing))
.middle(*width_mid, per_track(*width_mid, ||self.tracks_with_sizes_scrolled(), .middle(*width_mid, per_track(*width_mid, ||self.tracks_with_sizes_scrolled(),
|index, track|wrap( |index, track|wrap(
@ -126,7 +116,7 @@ impl<'a> ArrangerView<'a> {
/// Render device switches. /// Render device switches.
pub(crate) fn devices (&'a self) -> impl Content<TuiOut> + 'a { pub(crate) fn devices (&'a self) -> impl Content<TuiOut> + 'a {
let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self; let Self { width_side, width_mid, track_selected, is_editing, .. } = self;
Tryptich::top(1) Tryptich::top(1)
.left(*width_side, button_3("d", "devices", format!("{}", 0), *is_editing)) .left(*width_side, button_3("d", "devices", format!("{}", 0), *is_editing))
.right(*width_side, button_2("D", "add device", *is_editing)) .right(*width_side, button_2("D", "add device", *is_editing))

View file

@ -8,6 +8,8 @@ pub struct MidiEditor {
pub mode: PianoHorizontal, pub mode: PianoHorizontal,
} }
has!(Measure<TuiOut>: |self: MidiEditor|self.size);
impl std::fmt::Debug for MidiEditor { impl std::fmt::Debug for MidiEditor {
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
f.debug_struct("MidiEditor") f.debug_struct("MidiEditor")

View file

@ -1,7 +1,5 @@
use crate::*; use crate::*;
has_size!(<TuiOut>|self: MidiEditor|&self.size);
content!(TuiOut: |self: MidiEditor| { content!(TuiOut: |self: MidiEditor| {
self.autoscroll(); self.autoscroll();
//self.autozoom(); //self.autozoom();

View file

@ -18,6 +18,8 @@ pub struct PianoHorizontal {
pub keys_width: u16, pub keys_width: u16,
} }
has!(Measure<TuiOut>:|self:PianoHorizontal|self.size);
impl PianoHorizontal { impl PianoHorizontal {
pub fn new (clip: Option<&Arc<RwLock<MidiClip>>>) -> Self { pub fn new (clip: Option<&Arc<RwLock<MidiClip>>>) -> Self {
let size = Measure::new(); let size = Measure::new();
@ -227,8 +229,6 @@ impl PianoHorizontal {
} }
} }
has_size!(<TuiOut>|self:PianoHorizontal|&self.size);
impl TimeRange for PianoHorizontal { impl TimeRange for PianoHorizontal {
fn time_len (&self) -> &AtomicUsize { self.range.time_len() } fn time_len (&self) -> &AtomicUsize { self.range.time_len() }
fn time_zoom (&self) -> &AtomicUsize { self.range.time_zoom() } fn time_zoom (&self) -> &AtomicUsize { self.range.time_zoom() }

View file

@ -12,7 +12,8 @@ pub(crate) use std::path::PathBuf;
pub(crate) use std::error::Error; pub(crate) use std::error::Error;
pub(crate) use std::ffi::OsString; pub(crate) use std::ffi::OsString;
pub(crate) use ::tengri::{from, Usually, Perhaps, dsl::*, input::*, output::*, tui::{*, ratatui::prelude::*}}; pub(crate) use ::tengri::{from, Usually, Perhaps, Has};
pub(crate) use ::tengri::{dsl::*, input::*, output::*, tui::{*, ratatui::prelude::*}};
pub(crate) use ::tek_engine::*; pub(crate) use ::tek_engine::*;
pub(crate) use ::tek_engine::midi::{u7, LiveEvent, MidiMessage}; pub(crate) use ::tek_engine::midi::{u7, LiveEvent, MidiMessage};
pub(crate) use ::tek_engine::jack::{Control, ProcessScope, MidiWriter, RawMidi}; pub(crate) use ::tek_engine::jack::{Control, ProcessScope, MidiWriter, RawMidi};

View file

@ -9,24 +9,19 @@ pub(crate) use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering::Rela
pub(crate) use std::fmt::Debug; pub(crate) use std::fmt::Debug;
pub(crate) use std::ops::{Add, Sub, Mul, Div, Rem}; pub(crate) use std::ops::{Add, Sub, Mul, Div, Rem};
pub(crate) use ::tengri::{from, Usually, Perhaps, tui::*}; pub(crate) use ::tengri::{from, Usually, Perhaps, Has, tui::*};
pub use ::atomic_float; pub(crate) use atomic_float::*; pub use ::atomic_float; pub(crate) use atomic_float::*;
pub trait Has<T>: Send + Sync { //pub trait MaybeHas<T>: Send + Sync {
fn get (&self) -> &T; //fn get (&self) -> Option<&T>;
fn get_mut (&mut self) -> &mut T; //}
}
pub trait MaybeHas<T>: Send + Sync { //impl<T, U: Has<Option<T>>> MaybeHas<T> for U {
fn get (&self) -> Option<&T>; //fn get (&self) -> Option<&T> {
} //Has::<Option<T>>::get(self).as_ref()
//}
impl<T, U: Has<Option<T>>> MaybeHas<T> for U { //}
fn get (&self) -> Option<&T> {
Has::<Option<T>>::get(self).as_ref()
}
}
#[macro_export] macro_rules! has { #[macro_export] macro_rules! has {
($T:ty: |$self:ident : $S:ty| $x:expr) => { ($T:ty: |$self:ident : $S:ty| $x:expr) => {

2
deps/tengri vendored

@ -1 +1 @@
Subproject commit a9619ab9cea40aed3ec30483f4a7db03ca7fec9d Subproject commit 8bfd1a23a1f880a1d2fb104a158fc51f244acd6e