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

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

View file

@ -16,12 +16,9 @@
#![feature(type_changing_struct_update)]
#![feature(let_chains)]
#![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_device::{self, *};
pub use ::tengri::{Usually, Perhaps, Has};
pub use ::tengri::dsl::*;
pub use ::tengri::input::*;
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<Scene>: |self: App|self.project.scenes);
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_editor!(|self: App|{
editor = self.editor;
@ -152,8 +152,8 @@ impl App {
/// Various possible dialog overlays
#[derive(Clone, Debug)]
pub enum Dialog {
Help,
Menu,
Help(usize),
Menu(usize),
Device(usize),
Message(Message),
Save(Browser),
@ -216,29 +216,32 @@ impl App {
fn focus_pool_length (&self) -> bool {
matches!(self.project.pool.mode, Some(PoolMode::Length(..)))
}
fn dialog_device (&self) -> Dialog {
Dialog::Device(0) // TODO
fn dialog_none (&self) -> Option<Dialog> {
None
}
fn dialog_device_prev (&self) -> Dialog {
Dialog::Device(0) // TODO
fn dialog_device (&self) -> Option<Dialog> {
Some(Dialog::Device(0)) // TODO
}
fn dialog_device_next (&self) -> Dialog {
Dialog::Device(0) // TODO
fn dialog_device_prev (&self) -> Option<Dialog> {
Some(Dialog::Device(0)) // TODO
}
fn dialog_help (&self) -> Dialog {
Dialog::Help
fn dialog_device_next (&self) -> Option<Dialog> {
Some(Dialog::Device(0)) // TODO
}
fn dialog_menu (&self) -> Dialog {
Dialog::Menu
fn dialog_help (&self) -> Option<Dialog> {
Some(Dialog::Help(0))
}
fn dialog_save (&self) -> Dialog {
Dialog::Save(Default::default())
fn dialog_menu (&self) -> Option<Dialog> {
Some(Dialog::Menu(0))
}
fn dialog_load (&self) -> Dialog {
Dialog::Load(Default::default())
fn dialog_save (&self) -> Option<Dialog> {
Some(Dialog::Save(Default::default()))
}
fn dialog_options (&self) -> Dialog {
Dialog::Options
fn dialog_load (&self) -> Option<Dialog> {
Some(Dialog::Load(Default::default()))
}
fn dialog_options (&self) -> Option<Dialog> {
Some(Dialog::Options)
}
fn editor_pitch (&self) -> Option<u7> {
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(
Repeat(" "), Outer(true, Style::default().fg(Tui::g(96)))
.enclose(self.dialog.as_ref().map(|dialog|match dialog {
Dialog::Menu =>
Dialog::Menu(_) =>
self.view_dialog_menu().boxed(),
Dialog::Help =>
self.view_dialog_help().boxed(),
Dialog::Help(offset) =>
self.view_dialog_help(*offset).boxed(),
Dialog::Save(browser) =>
self.view_dialog_save().boxed(),
Dialog::Load(browser) =>
@ -84,12 +84,13 @@ impl App {
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)))
}
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,
||self.config.keys.layers.iter()
move||self.config.keys.layers.iter()
.filter_map(|a|(a.0)(self).then_some(a.1))
.flat_map(|a|a)
.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None })
.skip(offset)
.take(20),
|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))))),

View file

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

View file

@ -18,7 +18,7 @@ impl<'a> ArrangerView<'a> {
pub(crate) fn input_ports (&'a self) -> impl Content<TuiOut> + 'a {
Tryptich::top(1)
.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,
button_2("I", "add midi in", self.is_editing))
.middle(self.width_mid,
@ -96,7 +96,12 @@ impl<'a> ArrangerView<'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 {

View file

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

View file

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

View file

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

View file

@ -18,6 +18,8 @@ pub struct PianoHorizontal {
pub keys_width: u16,
}
has!(Measure<TuiOut>:|self:PianoHorizontal|self.size);
impl PianoHorizontal {
pub fn new (clip: Option<&Arc<RwLock<MidiClip>>>) -> Self {
let size = Measure::new();
@ -227,8 +229,6 @@ impl PianoHorizontal {
}
}
has_size!(<TuiOut>|self:PianoHorizontal|&self.size);
impl TimeRange for PianoHorizontal {
fn time_len (&self) -> &AtomicUsize { self.range.time_len() }
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::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::midi::{u7, LiveEvent, MidiMessage};
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::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 trait Has<T>: Send + Sync {
fn get (&self) -> &T;
fn get_mut (&mut self) -> &mut T;
}
//pub trait MaybeHas<T>: Send + Sync {
//fn get (&self) -> Option<&T>;
//}
pub trait MaybeHas<T>: Send + Sync {
fn get (&self) -> Option<&T>;
}
impl<T, U: Has<Option<T>>> MaybeHas<T> for U {
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 {
($T:ty: |$self:ident : $S:ty| $x:expr) => {