wip: add overlay for help/menu modals

This commit is contained in:
🪞👃🪞 2025-04-26 15:58:35 +03:00
parent fa2e08e81c
commit 38fb348d19
10 changed files with 323 additions and 234 deletions

View file

@ -1,6 +1,7 @@
use crate::*;
#[derive(Default, Debug)] pub struct Tek {
#[derive(Default, Debug)]
pub struct Tek {
/// Must not be dropped for the duration of the process
pub jack: Jack,
/// Source of time
@ -50,50 +51,20 @@ use crate::*;
// Cache of formatted strings
pub view_cache: Arc<RwLock<ViewCache>>,
// Input handler function
pub handler: Option<fn(&mut Self, &TuiIn)->Result<Option<bool>, Box<(dyn std::error::Error + 'static)>>>
pub handler: Option<fn(&mut Self, &TuiIn)->Result<Option<bool>, Box<(dyn std::error::Error + 'static)>>>,
// Modal overlay
pub modal: Option<Modal>
}
impl Tek {
pub(crate) fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
self.scene()?.clips.get(self.selected().track()?)?.clone()
}
pub(crate) fn toggle_loop (&mut self) {
if let Some(clip) = self.clip() {
clip.write().unwrap().toggle_loop()
}
}
pub(crate) fn activate (&mut self) -> Usually<()> {
let selected = self.selected().clone();
match selected {
Selection::Scene(s) => {
let mut clips = vec![];
for (t, _) in self.tracks().iter().enumerate() {
clips.push(self.scenes()[s].clips[t].clone());
}
for (t, track) in self.tracks_mut().iter_mut().enumerate() {
if track.player.play_clip.is_some() || clips[t].is_some() {
track.player.enqueue_next(clips[t].as_ref());
}
}
if self.clock().is_stopped() {
self.clock().play_from(Some(0))?;
}
},
Selection::Clip(t, s) => {
let clip = self.scenes()[s].clips[t].clone();
self.tracks_mut()[t].player.enqueue_next(clip.as_ref());
},
_ => {}
}
Ok(())
}
/// Add multiple tracks
pub fn tracks_add (
&mut self, count: usize, width: Option<usize>,
midi_from: &[PortConnect], midi_to: &[PortConnect],
&mut self,
count: usize,
width: Option<usize>,
midi_from: &[PortConnect],
midi_to: &[PortConnect],
) -> Usually<()> {
let jack = self.jack().clone();
let track_color_1 = ItemColor::random();
@ -108,8 +79,11 @@ impl Tek {
Ok(())
}
/// Add a track
pub fn track_add (
&mut self, name: Option<&str>, color: Option<ItemPalette>,
&mut self,
name: Option<&str>,
color: Option<ItemPalette>,
midi_froms: &[PortConnect],
midi_tos: &[PortConnect],
) -> Usually<(usize, &mut Track)> {
@ -139,6 +113,7 @@ impl Tek {
Ok((index, &mut self.tracks_mut()[index]))
}
/// Delete a track
pub fn track_del (&mut self, index: usize) {
self.tracks_mut().remove(index);
for scene in self.scenes_mut().iter_mut() {
@ -146,6 +121,7 @@ impl Tek {
}
}
/// Add multiple scenes
pub fn scenes_add (&mut self, n: usize) -> Usually<()> {
let scene_color_1 = ItemColor::random();
let scene_color_2 = ItemColor::random();
@ -157,6 +133,7 @@ impl Tek {
Ok(())
}
/// Add a scene
pub fn scene_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
-> Usually<(usize, &mut Scene)>
{
@ -170,6 +147,7 @@ impl Tek {
Ok((index, &mut self.scenes_mut()[index]))
}
/// Generate the default name for a new scene
pub fn scene_default_name (&self) -> Arc<str> {
format!("Sc{:3>}", self.scenes().len() + 1).into()
}
@ -216,6 +194,45 @@ impl Tek {
}
}
/// Get the active clip
pub(crate) fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
self.scene()?.clips.get(self.selected().track()?)?.clone()
}
/// Toggle looping for the active clip
pub(crate) fn toggle_loop (&mut self) {
if let Some(clip) = self.clip() {
clip.write().unwrap().toggle_loop()
}
}
/// Launch a clip or scene
pub(crate) fn activate (&mut self) -> Usually<()> {
let selected = self.selected().clone();
match selected {
Selection::Scene(s) => {
let mut clips = vec![];
for (t, _) in self.tracks().iter().enumerate() {
clips.push(self.scenes()[s].clips[t].clone());
}
for (t, track) in self.tracks_mut().iter_mut().enumerate() {
if track.player.play_clip.is_some() || clips[t].is_some() {
track.player.enqueue_next(clips[t].as_ref());
}
}
if self.clock().is_stopped() {
self.clock().play_from(Some(0))?;
}
},
Selection::Clip(t, s) => {
let clip = self.scenes()[s].clips[t].clone();
self.tracks_mut()[t].player.enqueue_next(clip.as_ref());
},
_ => {}
}
Ok(())
}
}
has_size!(<TuiOut>|self: Tek|&self.size);
@ -242,8 +259,16 @@ pub trait HasSelection {
fn selected_mut (&mut self) -> &mut Selection;
}
/// Various possible modal overlays
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum Modal {
Help,
Menu,
}
/// Represents the current user selection in the arranger
#[derive(PartialEq, Clone, Copy, Debug, Default)] pub enum Selection {
#[derive(PartialEq, Clone, Copy, Debug, Default)]
pub enum Selection {
/// The whole mix is selected
#[default] Mix,
/// A track is selected.
@ -272,10 +297,50 @@ impl Selection {
use Selection::*;
match self { Clip(t, _) => Some(*t), Track(t) => Some(*t), _ => None }
}
pub fn track_next (&self, len: usize) -> Self {
match self {
Selection::Mix => Selection::Track(0),
Selection::Track(t) if t + 1 < len => Selection::Track(t + 1),
Selection::Track(t) => Selection::Mix,
Selection::Scene(s) => Selection::Clip(0, *s),
Selection::Clip(t, s) if t + 1 < len => Selection::Clip(t + 1, *s),
Selection::Clip(t, s) => Selection::Scene(*s),
}
}
pub fn track_prev (&self) -> Self {
match self {
Selection::Mix => Selection::Mix,
Selection::Scene(s) => Selection::Scene(*s),
Selection::Track(0) => Selection::Mix,
Selection::Track(t) => Selection::Track(t - 1),
Selection::Clip(0, s) => Selection::Scene(*s),
Selection::Clip(t, s) => Selection::Clip(t - 1, *s),
}
}
pub fn scene (&self) -> Option<usize> {
use Selection::*;
match self { Clip(_, s) => Some(*s), Scene(s) => Some(*s), _ => None }
}
pub fn scene_next (&self, len: usize) -> Self {
match self {
Selection::Mix => Selection::Scene(0),
Selection::Track(t) => Selection::Clip(*t, 0),
Selection::Scene(s) if s + 1 < len => Selection::Scene(s + 1),
Selection::Scene(s) => Selection::Mix,
Selection::Clip(t, s) if s + 1 < len => Selection::Clip(*t, s + 1),
Selection::Clip(t, s) => Selection::Track(*t),
}
}
pub fn scene_prev (&self) -> Self {
match self {
Selection::Mix => Selection::Mix,
Selection::Track(t) => Selection::Track(*t),
Selection::Scene(0) => Selection::Mix,
Selection::Scene(s) => Selection::Scene(s - 1),
Selection::Clip(t, 0) => Selection::Track(*t),
Selection::Clip(t, s) => Selection::Clip(*t, s - 1),
}
}
pub fn describe (&self, tracks: &[Track], scenes: &[Scene]) -> Arc<str> {
format!("{}", match self {
Self::Mix => "Everything".to_string(),