use new AsRefOpt/AsMutOpt glue traits

This commit is contained in:
okay stopped screaming 2026-02-23 22:49:20 +02:00
parent 6295f2e601
commit ab90129f4c
7 changed files with 661 additions and 740 deletions

View file

@ -125,24 +125,55 @@ pub trait HasMidiClip {
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>>;
}
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }
fn clock (&self) -> &Clock { self.as_ref() }
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }
}
pub trait HasDevices: AsRef<Vec<Device>> + AsMut<Vec<Device>> {
fn devices_mut (&mut self) -> &mut Vec<Device> { self.as_mut() }
fn devices (&self) -> &Vec<Device> { self.as_ref() }
}
pub trait HasSelection: AsRef<Selection> + AsMut<Selection> {
fn selection_mut (&mut self) -> &mut Selection { self.as_mut() }
fn selection (&self) -> &Selection { self.as_ref() }
fn devices_mut (&mut self) -> &mut Vec<Device> { self.as_mut() }
}
pub trait HasSequencer: AsRef<Sequencer> + AsMut<Sequencer> {
fn sequencer_mut (&mut self) -> &mut Sequencer { self.as_mut() }
fn sequencer (&self) -> &Sequencer { self.as_ref() }
}
pub trait HasScene: AsRef<Option<Scene>> + AsMut<Option<Scene>> {
fn scene_mut (&mut self) -> &mut Option<Scene> { self.as_mut() }
fn scene (&self) -> Option<&Scene> { self.as_ref() }
pub trait HasSceneScroll: HasScenes { fn scene_scroll (&self) -> usize; }
pub trait HasTrackScroll: HasTracks { fn track_scroll (&self) -> usize; }
pub trait HasScene: AsRefOpt<Scene> + AsMutOpt<Scene> {
fn scene_mut (&mut self) -> Option<&mut Scene> { self.as_mut_opt() }
fn scene (&self) -> Option<&Scene> { self.as_ref_opt() }
}
pub trait HasSelection: AsRef<Selection> + AsMut<Selection> {
fn selection (&self) -> &Selection { self.as_ref() }
fn selection_mut (&mut self) -> &mut Selection { self.as_mut() }
/// Get the active track
#[cfg(feature = "track")]
fn selected_track (&self) -> Option<&Track> where Self: HasTracks {
let index = self.selection().track()?;
self.tracks().get(index)
}
/// Get a mutable reference to the active track
#[cfg(feature = "track")]
fn selected_track_mut (&mut self) -> Option<&mut Track> where Self: HasTracks {
let index = self.selection().track()?;
self.tracks_mut().get_mut(index)
}
/// Get the active scene
#[cfg(feature = "scene")]
fn selected_scene (&self) -> Option<&Scene> where Self: HasScenes {
let index = self.selection().scene()?;
self.scenes().get(index)
}
/// Get a mutable reference to the active scene
#[cfg(feature = "scene")]
fn selected_scene_mut (&mut self) -> Option<&mut Scene> where Self: HasScenes {
let index = self.selection().scene()?;
self.scenes_mut().get_mut(index)
}
/// Get the active clip
#[cfg(feature = "clip")]
fn selected_clip (&self) -> Option<Arc<RwLock<MidiClip>>> where Self: HasScenes + HasTracks {
self.selected_scene()?.clips.get(self.selection().track()?)?.clone()
}
}
pub trait HasScenes: AsRef<Vec<Scene>> + AsMut<Vec<Scene>> {
fn scenes (&self) -> &Vec<Scene> { self.as_ref() }
@ -150,12 +181,30 @@ pub trait HasScenes: AsRef<Vec<Scene>> + AsMut<Vec<Scene>> {
/// Generate the default name for a new scene
fn scene_default_name (&self) -> Arc<str> { format!("s{:3>}", self.scenes().len() + 1).into() }
fn scene_longest_name (&self) -> usize { self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max) }
}
pub trait HasSceneScroll: HasScenes {
fn scene_scroll (&self) -> usize;
}
pub trait HasTrackScroll: HasTracks {
fn track_scroll (&self) -> usize;
/// Add multiple scenes
fn scenes_add (&mut self, n: usize) -> Usually<()> where Self: HasTracks {
let scene_color_1 = ItemColor::random();
let scene_color_2 = ItemColor::random();
for i in 0..n {
let _ = self.scene_add(None, Some(
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
))?;
}
Ok(())
}
/// Add a scene
fn scene_add (&mut self, name: Option<&str>, color: Option<ItemTheme>)
-> Usually<(usize, &mut Scene)> where Self: HasTracks
{
let scene = Scene {
name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()),
clips: vec![None;self.tracks().len()],
color: color.unwrap_or_else(ItemTheme::random),
};
self.scenes_mut().push(scene);
let index = self.scenes().len() - 1;
Ok((index, &mut self.scenes_mut()[index]))
}
}
pub trait HasWidth {
const MIN_WIDTH: usize;
@ -170,39 +219,26 @@ pub trait HasMidiBuffers {
}
/// ```
/// use tek::{MidiEditor, HasEditor, tengri::Has};
/// use tek::{*, tengri::*};
///
/// let mut host = TestEditorHost(Some(MidiEditor::default()));
/// struct TestEditorHost(Option<MidiEditor>);
/// impl AsRef<Option<MidiEditor>> for TestEditorHost {
/// fn get (&self) -> &Option<MidiEditor> { &self.0 }
/// fn get_mut (&mut self) -> &mut Option<MidiEditor> { &mut self.0 }
/// }
/// struct Test(Option<MidiEditor>);
/// impl_as_ref_opt!(MidiEditor: |self: Test|self.0.as_ref());
/// impl_as_mut_opt!(MidiEditor: |self: Test|self.0.as_mut());
///
/// let mut host = Test(Some(MidiEditor::default()));
/// let _ = host.editor();
/// let _ = host.editor_mut();
/// let _ = host.is_editing();
/// let _ = host.editor_w();
/// let _ = host.editor_h();
/// ```
pub trait HasEditor: AsRef<Option<MidiEditor>> {
fn editor (&self) -> Option<&MidiEditor> {
self.get().as_ref()
}
fn editor_mut (&mut self) -> Option<&mut MidiEditor> {
self.get_mut().as_mut()
}
fn is_editing (&self) -> bool {
self.editor().is_some()
}
fn editor_w (&self) -> usize {
self.editor().map(|e|e.size.w()).unwrap_or(0) as usize
}
fn editor_h (&self) -> usize {
self.editor().map(|e|e.size.h()).unwrap_or(0) as usize
}
pub trait HasEditor: AsRefOpt<MidiEditor> + AsMutOpt<MidiEditor> {
fn editor (&self) -> Option<&MidiEditor> { self.as_ref_opt() }
fn editor_mut (&mut self) -> Option<&mut MidiEditor> { self.as_mut_opt() }
fn is_editing (&self) -> bool { self.editor().is_some() }
fn editor_w (&self) -> usize { self.editor().map(|e|e.size.w()).unwrap_or(0) as usize }
fn editor_h (&self) -> usize { self.editor().map(|e|e.size.h()).unwrap_or(0) as usize }
}
pub trait HasClips {
fn clips <'a> (&'a self) -> std::sync::RwLockReadGuard<'a, ClipPool>;
fn clips_mut <'a> (&'a self) -> std::sync::RwLockWriteGuard<'a, ClipPool>;
@ -212,7 +248,6 @@ pub trait HasClips {
(self.clips().len() - 1, clip)
}
}
/// Trait for thing that may receive MIDI.
pub trait HasMidiIns {
fn midi_ins (&self) -> &Vec<MidiInput>;
@ -237,7 +272,6 @@ pub trait HasMidiIns {
})
}
}
/// Trait for thing that may output MIDI.
pub trait HasMidiOuts {
fn midi_outs (&self) -> &Vec<MidiOutput>;
@ -259,9 +293,7 @@ pub trait HasMidiOuts {
}
}
}
impl<T: AsRef<Vec<Track>> + AsMut<Vec<Track>> + Send + Sync> HasTracks for T {}
pub trait HasTracks: AsRef<Vec<Track>> + AsMut<Vec<Track>> + Send + Sync {
pub trait HasTracks: AsRef<Vec<Track>> + AsMut<Vec<Track>> {
fn tracks (&self) -> &Vec<Track> { self.as_ref() }
fn tracks_mut (&mut self) -> &mut Vec<Track> { self.as_mut() }
/// Run audio callbacks for every track and every device
@ -292,10 +324,9 @@ pub trait HasTracks: AsRef<Vec<Track>> + AsMut<Vec<Track>> + Send + Sync {
/// Spacing between tracks.
const TRACK_SPACING: usize = 0;
}
pub trait HasTrack {
fn track (&self) -> Option<&Track>;
fn track_mut (&mut self) -> Option<&mut Track>;
pub trait HasTrack: AsRefOpt<Track> + AsMutOpt<Track> {
fn track (&self) -> Option<&Track> { self.as_ref_opt() }
fn track_mut (&mut self) -> Option<&mut Track> { self.as_mut_opt() }
#[cfg(feature = "port")] fn view_midi_ins_status <'a> (&'a self, theme: ItemTheme) -> impl Content<TuiOut> + 'a {
self.track().map(move|track|view_ports_status(theme, "MIDI ins: ", &track.sequencer.midi_ins))
}
@ -523,33 +554,6 @@ pub trait MidiViewer: Measured<TuiOut> + MidiRange + MidiPoint + Debug + Send +
}
}
pub trait AddScene: HasScenes + HasTracks {
/// Add multiple scenes
fn scenes_add (&mut self, n: usize) -> Usually<()> {
let scene_color_1 = ItemColor::random();
let scene_color_2 = ItemColor::random();
for i in 0..n {
let _ = self.scene_add(None, Some(
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
))?;
}
Ok(())
}
/// Add a scene
fn scene_add (&mut self, name: Option<&str>, color: Option<ItemTheme>)
-> Usually<(usize, &mut Scene)>
{
let scene = Scene {
name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()),
clips: vec![None;self.tracks().len()],
color: color.unwrap_or_else(ItemTheme::random),
};
self.scenes_mut().push(scene);
let index = self.scenes().len() - 1;
Ok((index, &mut self.scenes_mut()[index]))
}
}
pub trait ClipsView: TracksView + ScenesView {
fn view_scenes_clips <'a> (&'a self)