mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
This commit is contained in:
parent
eb0547dc37
commit
2858b01bd4
12 changed files with 379 additions and 391 deletions
|
|
@ -2,9 +2,9 @@ use crate::*;
|
|||
|
||||
impl Arrangement {
|
||||
pub fn view_inputs <'a> (&'a self, theme: ItemTheme) -> impl Content<TuiOut> + 'a {
|
||||
let mut h = 1u16;
|
||||
let mut h = 0;
|
||||
for track in self.tracks().iter() {
|
||||
h = h.max(track.sequencer.midi_ins.len() as u16);
|
||||
h = h.max(self.midi_ins.len() as u16);
|
||||
}
|
||||
let h = h + 1;
|
||||
self.view_track_row_section(
|
||||
|
|
@ -153,12 +153,22 @@ pub trait TracksView:
|
|||
fn view_track_names (&self, theme: ItemTheme) -> impl Content<TuiOut> {
|
||||
self.view_track_row_section(
|
||||
theme,
|
||||
button_3("t", "rack ", if let Some(track) = self.selection().track() {
|
||||
format!("{track}/{}", self.tracks().len())
|
||||
} else {
|
||||
format!("{}", self.tracks().len())
|
||||
}, false),
|
||||
button_2("T", "+", false),
|
||||
Bsp::s(
|
||||
button_3("t", "rack ", if let Some(track) = self.selection().track() {
|
||||
format!("{track}/{}", self.tracks().len())
|
||||
} else {
|
||||
format!("{}", self.tracks().len())
|
||||
}, false),
|
||||
button_3("s", "cene ", if let Some(scene) = self.selection().scene() {
|
||||
format!("{scene}/{}", self.scenes().len())
|
||||
} else {
|
||||
format!("{}", self.scenes().len())
|
||||
}, false)
|
||||
),
|
||||
Bsp::s(
|
||||
button_2("T", "+", false),
|
||||
button_2("S", "+", false),
|
||||
),
|
||||
Tui::bg(theme.darker.rgb, Fixed::y(2, Fill::x(
|
||||
Stack::east(move|add: &mut dyn FnMut(&dyn Render<TuiOut>)|{
|
||||
for (index, track, x1, x2) in self.tracks_with_sizes() {
|
||||
|
|
@ -256,7 +266,7 @@ pub trait ScenesView:
|
|||
self.scenes().iter().enumerate().skip(self.scene_scroll()).map_while(move|(s, 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() {
|
||||
if y + height <= self.clips_size().h() {
|
||||
let data = (s, scene, y, y + height);
|
||||
y += height;
|
||||
Some(data)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@ use crate::*;
|
|||
use std::path::PathBuf;
|
||||
use std::ffi::OsString;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BrowserTarget {
|
||||
SaveProject,
|
||||
LoadProject,
|
||||
ImportSample(Arc<RwLock<Option<Sample>>>),
|
||||
ExportSample(Arc<RwLock<Option<Sample>>>),
|
||||
ImportClip(Arc<RwLock<Option<MidiClip>>>),
|
||||
ExportClip(Arc<RwLock<Option<MidiClip>>>),
|
||||
}
|
||||
|
||||
/// Browses for phrase to import/export
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Browser {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
use crate::*;
|
||||
|
||||
pub fn device_kinds () -> &'static [&'static str] {
|
||||
&[
|
||||
"Sampler",
|
||||
"Plugin (LV2)",
|
||||
]
|
||||
}
|
||||
|
||||
impl<T: Has<Vec<Device>> + Has<Track>> HasDevices for T {
|
||||
fn devices (&self) -> &Vec<Device> {
|
||||
self.get()
|
||||
|
|
|
|||
113
crates/device/src/dialog.rs
Normal file
113
crates/device/src/dialog.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
use crate::*;
|
||||
|
||||
/// Various possible dialog overlays
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Dialog {
|
||||
Help(usize),
|
||||
Menu(usize),
|
||||
Device(usize),
|
||||
Message(Message),
|
||||
Browser(BrowserTarget, Browser),
|
||||
Options,
|
||||
}
|
||||
|
||||
/// Various possible messages
|
||||
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||
pub enum Message {
|
||||
FailedToAddDevice,
|
||||
}
|
||||
|
||||
content!(TuiOut: |self: Message| match self {
|
||||
Self::FailedToAddDevice => "Failed to add device."
|
||||
});
|
||||
|
||||
content!(TuiOut: |self: Dialog| match self {
|
||||
Self::Menu(_) =>
|
||||
self.view_dialog_menu().boxed(),
|
||||
Self::Help(offset) =>
|
||||
self.view_dialog_help(*offset).boxed(),
|
||||
Self::Browser(target, browser) =>
|
||||
self.view_dialog_browser(target, browser).boxed(),
|
||||
Self::Options =>
|
||||
self.view_dialog_options().boxed(),
|
||||
Self::Device(index) =>
|
||||
self.view_dialog_device(*index).boxed(),
|
||||
Self::Message(message) =>
|
||||
self.view_dialog_message(message).boxed(),
|
||||
});
|
||||
|
||||
impl Dialog {
|
||||
pub fn view_dialog_menu (&self) -> impl Content<TuiOut> {
|
||||
let options = ||["Projects", "Settings", "Help", "Quit"].iter();
|
||||
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, offset: usize) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(Tui::bold(true, "Help"), "FIXME")
|
||||
//Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1,
|
||||
//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))))),
|
||||
//Bsp::e(" ", Align::w(format!("{}", b.0.0.trim()))))))))))
|
||||
}
|
||||
pub fn view_dialog_device (&self, index: usize) -> impl Content<TuiOut> + use<'_> {
|
||||
let choices = ||device_kinds().iter();
|
||||
let choice = move|label, i|
|
||||
Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) },
|
||||
Bsp::e(if i == index { "[ " } else { " " },
|
||||
Bsp::w(if i == index { " ]" } else { " " },
|
||||
label))));
|
||||
Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice))
|
||||
}
|
||||
pub fn view_dialog_message <'a> (&'a self, message: &'a Message) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(message, Bsp::s("", "[ OK ]"))
|
||||
}
|
||||
pub fn view_dialog_browser <'a> (&'a self, target: &BrowserTarget, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Padding::xy(3, 1, Fill::x(Align::w(FieldV(
|
||||
Default::default(),
|
||||
match target {
|
||||
BrowserTarget::SaveProject => "Save project:",
|
||||
BrowserTarget::LoadProject => "Load project:",
|
||||
BrowserTarget::ImportSample(_) => "Import sample:",
|
||||
BrowserTarget::ExportSample(_) => "Export sample:",
|
||||
BrowserTarget::ImportClip(_) => "Import clip:",
|
||||
BrowserTarget::ExportClip(_) => "Export clip:",
|
||||
},
|
||||
Shrink::x(3, Fixed::y(1, Tui::fg(Tui::g(96), RepeatH("🭻")))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_load <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Load project: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_export <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Export: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_import <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Import: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_options <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
||||
"TODO"
|
||||
}
|
||||
}
|
||||
|
|
@ -14,54 +14,27 @@ pub(crate) use std::error::Error;
|
|||
pub(crate) use std::ffi::OsString;
|
||||
|
||||
pub(crate) use ::tengri::{from, has, maybe_has, Usually, Perhaps, Has, MaybeHas};
|
||||
pub(crate) use ::tengri::{dsl::*, input::*, output::*, tui::{*, ratatui::prelude::*}};
|
||||
pub(crate) use ::tengri::{dsl::*, input::*, output::{*, Margin}, 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};
|
||||
pub(crate) use ratatui::{prelude::Rect, widgets::{Widget, canvas::{Canvas, Line}}};
|
||||
pub(crate) use Color::*;
|
||||
|
||||
mod device;
|
||||
pub use self::device::*;
|
||||
mod device; pub use self::device::*;
|
||||
mod dialog; pub use self::dialog::*;
|
||||
|
||||
#[cfg(feature = "arranger")] mod arranger;
|
||||
#[cfg(feature = "arranger")] pub use self::arranger::*;
|
||||
|
||||
#[cfg(feature = "browser")] mod browser;
|
||||
#[cfg(feature = "browser")] pub use self::browser::*;
|
||||
|
||||
#[cfg(feature = "clock")] mod clock;
|
||||
#[cfg(feature = "clock")] pub use self::clock::*;
|
||||
|
||||
#[cfg(feature = "editor")] mod editor;
|
||||
#[cfg(feature = "editor")] pub use self::editor::*;
|
||||
|
||||
#[cfg(feature = "pool")] mod pool;
|
||||
#[cfg(feature = "pool")] pub use self::pool::*;
|
||||
|
||||
#[cfg(feature = "sequencer")] mod sequencer;
|
||||
#[cfg(feature = "sequencer")] pub use self::sequencer::*;
|
||||
|
||||
#[cfg(feature = "sampler")] mod sampler;
|
||||
#[cfg(feature = "sampler")] pub use self::sampler::*;
|
||||
|
||||
#[cfg(feature = "meter")] mod meter;
|
||||
#[cfg(feature = "meter")] pub use self::meter::*;
|
||||
|
||||
#[cfg(feature = "mixer")] mod mixer;
|
||||
#[cfg(feature = "mixer")] pub use self::mixer::*;
|
||||
|
||||
#[cfg(feature = "lv2")] mod lv2;
|
||||
#[cfg(feature = "lv2")] pub use self::lv2::*;
|
||||
|
||||
#[cfg(feature = "sf2")] mod sf2;
|
||||
#[cfg(feature = "sf2")] pub use self::sf2::*;
|
||||
|
||||
#[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::*;
|
||||
#[cfg(feature = "arranger")] mod arranger; #[cfg(feature = "arranger")] pub use self::arranger::*;
|
||||
#[cfg(feature = "browser")] mod browser; #[cfg(feature = "browser")] pub use self::browser::*;
|
||||
#[cfg(feature = "clock")] mod clock; #[cfg(feature = "clock")] pub use self::clock::*;
|
||||
#[cfg(feature = "editor")] mod editor; #[cfg(feature = "editor")] pub use self::editor::*;
|
||||
#[cfg(feature = "pool")] mod pool; #[cfg(feature = "pool")] pub use self::pool::*;
|
||||
#[cfg(feature = "sequencer")] mod sequencer; #[cfg(feature = "sequencer")] pub use self::sequencer::*;
|
||||
#[cfg(feature = "sampler")] mod sampler; #[cfg(feature = "sampler")] pub use self::sampler::*;
|
||||
#[cfg(feature = "meter")] mod meter; #[cfg(feature = "meter")] pub use self::meter::*;
|
||||
#[cfg(feature = "mixer")] mod mixer; #[cfg(feature = "mixer")] pub use self::mixer::*;
|
||||
#[cfg(feature = "lv2")] mod lv2; #[cfg(feature = "lv2")] pub use self::lv2::*;
|
||||
#[cfg(feature = "sf2")] mod sf2; #[cfg(feature = "sf2")] pub use self::sf2::*;
|
||||
#[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::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue