tek/crates/tek_tui/src/lib.rs
2024-11-25 18:16:39 +01:00

242 lines
7.5 KiB
Rust

pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
pub(crate) use tek_core::{*, jack::*};
pub(crate) use tek_api::*;
pub(crate) use std::collections::BTreeMap;
pub(crate) use std::sync::{Arc, Mutex, RwLock};
pub(crate) use std::path::PathBuf;
pub(crate) use std::ffi::OsString;
pub(crate) use std::fs::read_dir;
submod! {
tui_focus
tui_menu
tui_status
tui_app_arranger
tui_app_sequencer
tui_app_transport
tui_jack_transport
tui_jack_sequencer
tui_jack_arranger
tui_control_arranger
tui_control_file_browser
tui_control_phrase_editor
tui_control_phrase_length
tui_control_phrase_list
tui_control_phrase_rename
tui_control_sequencer
tui_control_transport
tui_model_arranger
tui_model_clock
tui_model_file_browser
tui_model_phrase_editor
tui_model_phrase_length
tui_model_phrase_list
tui_model_phrase_player
tui_view_arranger
tui_view_file_browser
tui_view_phrase_editor
tui_view_phrase_length
tui_view_phrase_list
tui_view_sequencer
tui_view_transport
}
pub fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> {
use KeyCode::{Tab, BackTab, Up, Down, Left, Right, Enter, Esc};
Some(match input.event() {
key!(Tab) => FocusCommand::Next,
key!(Shift-Tab) => FocusCommand::Prev,
key!(BackTab) => FocusCommand::Prev,
key!(Shift-BackTab) => FocusCommand::Prev,
key!(Up) => FocusCommand::Up,
key!(Down) => FocusCommand::Down,
key!(Left) => FocusCommand::Left,
key!(Right) => FocusCommand::Right,
key!(Enter) => FocusCommand::Enter,
key!(Esc) => FocusCommand::Exit,
_ => return None
})
}
pub struct TuiTheme;
impl TuiTheme {
pub fn border_bg () -> Color {
Color::Rgb(40, 50, 30)
}
pub fn border_fg (focused: bool) -> Color {
if focused { Color::Rgb(100, 110, 40) } else { Color::Rgb(70, 80, 50) }
}
pub fn title_fg (focused: bool) -> Color {
if focused { Color::Rgb(150, 160, 90) } else { Color::Rgb(120, 130, 100) }
}
pub fn separator_fg (_: bool) -> Color {
Color::Rgb(0, 0, 0)
}
pub const fn hotkey_fg () -> Color {
Color::Rgb(255, 255, 0)
}
pub fn mode_bg () -> Color {
Color::Rgb(150, 160, 90)
}
pub fn mode_fg () -> Color {
Color::Rgb(255, 255, 255)
}
pub fn status_bar_bg () -> Color {
Color::Rgb(28, 35, 25)
}
}
macro_rules! impl_clock_api {
($Struct:ident $(:: $field:ident)*) => {
impl ClockApi for $Struct {
fn quant (&self) -> &Arc<Quantize> {
&self$(.$field)*.quant
}
fn sync (&self) -> &Arc<LaunchSync> {
&self$(.$field)*.sync
}
fn current (&self) -> &Arc<Instant> {
&self$(.$field)*.current
}
fn transport_handle (&self) -> &Arc<Transport> {
&self$(.$field)*.transport
}
fn transport_state (&self) -> &Arc<RwLock<Option<TransportState>>> {
&self$(.$field)*.playing
}
fn transport_offset (&self) -> &Arc<RwLock<Option<(usize, usize)>>> {
&self$(.$field)*.started
}
}
}
}
macro_rules! impl_midi_player {
($Struct:ident $(:: $field:ident)*) => {
impl HasPhrase for $Struct {
fn reset (&self) -> bool {
self$(.$field)*.reset
}
fn reset_mut (&mut self) -> &mut bool {
&mut self$(.$field)*.reset
}
fn play_phrase (&self) -> &Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
&self$(.$field)*.play_phrase
}
fn play_phrase_mut (&mut self) -> &mut Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
&mut self$(.$field)*.play_phrase
}
fn next_phrase (&self) -> &Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
&self$(.$field)*.next_phrase
}
fn next_phrase_mut (&mut self) -> &mut Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
&mut self$(.$field)*.next_phrase
}
}
impl MidiInputApi for $Struct {
fn midi_ins (&self) -> &Vec<Port<jack::MidiIn>> {
&self$(.$field)*.midi_ins
}
fn midi_ins_mut (&mut self) -> &mut Vec<Port<jack::MidiIn>> {
&mut self$(.$field)*.midi_ins
}
fn recording (&self) -> bool {
self$(.$field)*.recording
}
fn recording_mut (&mut self) -> &mut bool {
&mut self$(.$field)*.recording
}
fn monitoring (&self) -> bool {
self$(.$field)*.monitoring
}
fn monitoring_mut (&mut self) -> &mut bool {
&mut self$(.$field)*.monitoring
}
fn overdub (&self) -> bool {
self$(.$field)*.overdub
}
fn overdub_mut (&mut self) -> &mut bool {
&mut self$(.$field)*.overdub
}
fn notes_in (&self) -> &Arc<RwLock<[bool; 128]>> {
&self$(.$field)*.notes_in
}
}
impl MidiOutputApi for $Struct {
fn midi_outs (&self) -> &Vec<Port<jack::MidiOut>> {
&self$(.$field)*.midi_outs
}
fn midi_outs_mut (&mut self) -> &mut Vec<Port<jack::MidiOut>> {
&mut self$(.$field)*.midi_outs
}
fn midi_note (&mut self) -> &mut Vec<u8> {
&mut self$(.$field)*.note_buf
}
fn notes_out (&self) -> &Arc<RwLock<[bool; 128]>> {
&self$(.$field)*.notes_in
}
}
impl MidiPlayerApi for $Struct {}
}
}
impl_clock_api!(TransportTui::clock);
impl_clock_api!(SequencerTui::clock);
impl_clock_api!(ArrangerTui::clock);
impl_clock_api!(PhrasePlayerModel::clock);
impl_clock_api!(ArrangerTrack::player::clock);
impl_midi_player!(SequencerTui::player);
impl_midi_player!(ArrangerTrack::player);
impl_midi_player!(PhrasePlayerModel);
use std::fmt::{Debug, Formatter, Error};
type DebugResult = std::result::Result<(), Error>;
impl Debug for ClockModel {
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
f.debug_struct("editor")
.field("playing", &self.playing)
.field("started", &self.started)
.field("current", &self.current)
.field("quant", &self.quant)
.field("sync", &self.sync)
.finish()
}
}
impl Debug for TransportTui {
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
f.debug_struct("Measure")
.field("jack", &self.jack)
.field("size", &self.size)
.field("cursor", &self.cursor)
.finish()
}
}
impl Debug for PhraseEditorModel {
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
f.debug_struct("editor")
.field("note_axis", &self.time_axis)
.field("time_axis", &self.note_axis)
.finish()
}
}
impl Debug for PhrasePlayerModel {
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
f.debug_struct("editor")
.field("clock", &self.clock)
.field("play_phrase", &self.play_phrase)
.field("next_phrase", &self.next_phrase)
.finish()
}
}