mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-10-08 18:56:42 +02:00
wip: simplify clip traits to implement upsert
This commit is contained in:
parent
8b96ddb411
commit
c5d6ce24b2
5 changed files with 178 additions and 184 deletions
17
src/app.rs
17
src/app.rs
|
|
@ -75,7 +75,6 @@ pub struct App {
|
||||||
pub project: Project,
|
pub project: Project,
|
||||||
/// Error, if any
|
/// Error, if any
|
||||||
pub error: Arc<RwLock<Option<Arc<str>>>>,
|
pub error: Arc<RwLock<Option<Arc<str>>>>,
|
||||||
|
|
||||||
#[cfg(feature = "prof2")]
|
#[cfg(feature = "prof2")]
|
||||||
/// Tracing guard
|
/// Tracing guard
|
||||||
pub guard: Option<tracing_flame::FlushGuard<std::io::BufWriter<std::fs::File>>>,
|
pub guard: Option<tracing_flame::FlushGuard<std::io::BufWriter<std::fs::File>>>,
|
||||||
|
|
@ -278,7 +277,6 @@ impl_has!(Dialog: |self: App|self.dialog);
|
||||||
impl_has!(Jack<'static>: |self: App|self.jack);
|
impl_has!(Jack<'static>: |self: App|self.jack);
|
||||||
impl_has!(Pool: |self: App|self.pool);
|
impl_has!(Pool: |self: App|self.pool);
|
||||||
impl_has!(Selection: |self: App|self.project.selection);
|
impl_has!(Selection: |self: App|self.project.selection);
|
||||||
impl_has_clips!( |self: App|self.pool.clips);
|
|
||||||
impl_as_ref!(Option<MidiEditor>: |self: App|self.project.as_ref());
|
impl_as_ref!(Option<MidiEditor>: |self: App|self.project.as_ref());
|
||||||
impl_as_mut!(Option<MidiEditor>: |self: App|self.project.as_mut());
|
impl_as_mut!(Option<MidiEditor>: |self: App|self.project.as_mut());
|
||||||
|
|
||||||
|
|
@ -287,6 +285,21 @@ primitive!(u16: try_to_u16);
|
||||||
primitive!(usize: try_to_usize);
|
primitive!(usize: try_to_usize);
|
||||||
primitive!(isize: try_to_isize);
|
primitive!(isize: try_to_isize);
|
||||||
|
|
||||||
|
impl HasClips for App {
|
||||||
|
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||||
|
self.project.clip()
|
||||||
|
}
|
||||||
|
fn clip_mut (&self) -> &mut Option<Arc<RwLock<MidiClip>>> {
|
||||||
|
self.project.clip_mut()
|
||||||
|
}
|
||||||
|
fn clips <'a> (&'a self) -> RwLockReadGuard<'a, Clips> {
|
||||||
|
self.project.clips()
|
||||||
|
}
|
||||||
|
fn clips_mut <'a> (&'a self) -> RwLockWriteGuard<'a, Clips> {
|
||||||
|
self.project.clips_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tui_keys!(self: App, input {
|
tui_keys!(self: App, input {
|
||||||
#[cfg(feature = "prof2")] profiling::scope!("App::tui_keys!");
|
#[cfg(feature = "prof2")] profiling::scope!("App::tui_keys!");
|
||||||
Self::input_command(self, input)
|
Self::input_command(self, input)
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,10 @@ impl Binds {
|
||||||
let expr = item.expr()?;
|
let expr = item.expr()?;
|
||||||
let head = expr.head()?;
|
let head = expr.head()?;
|
||||||
if let Some(event) = TuiKey::from_dsl(&head)?.to_crossterm() {
|
if let Some(event) = TuiKey::from_dsl(&head)?.to_crossterm() {
|
||||||
|
let mut commands: Vec<Arc<str>> = vec![];
|
||||||
|
item.expr()?.tail()?.each((), |_, def|Ok(commands.push(def.into())))?;
|
||||||
map.add(TuiEvent(event), Binding {
|
map.add(TuiEvent(event), Binding {
|
||||||
commands: [item.expr()?.tail()?.unwrap_or_default().into()].into(),
|
commands: commands.into(),
|
||||||
condition: None,
|
condition: None,
|
||||||
description: None,
|
description: None,
|
||||||
source: None
|
source: None
|
||||||
|
|
|
||||||
208
src/midi_clip.rs
208
src/midi_clip.rs
|
|
@ -1,35 +1,16 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub fn get_opt_arc_rwlock_midiclip <'a> (state: &App, src: impl Language)
|
pub type Clips = Vec<Arc<RwLock<MidiClip>>>;
|
||||||
-> Perhaps<Option<Arc<RwLock<MidiClip>>>>
|
|
||||||
{
|
|
||||||
eval_word(src, |word|Ok(match word {
|
|
||||||
|
|
||||||
":selected" if let Selection::TrackClip {
|
pub trait HasClips {
|
||||||
track, scene
|
/// Active clip slot (immutable). Use this to access or modify current clip.
|
||||||
} = state.selection() => {
|
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>>;
|
||||||
state.scenes()[*scene].clips[*track].clone()
|
/// Active clip slot (mutable). Use this to place or remove a clip at current position.
|
||||||
},
|
fn clip_mut (&self) -> &mut Option<Arc<RwLock<MidiClip>>>;
|
||||||
|
/// Clip list (immutable). Use this to access or modify more than one clip.
|
||||||
//":selected-or-create" if let Selection::TrackClip {
|
fn clips <'a> (&'a self) -> RwLockReadGuard<'a, Clips>;
|
||||||
//track, scene
|
/// Clip list (mutable). Use this to define or delete new clips.
|
||||||
//} = state.selection() => Some(if let Some(Some(clip)) = state.scenes()[*scene].clips.get(*track) {
|
fn clips_mut <'a> (&'a self) -> RwLockWriteGuard<'a, Clips>;
|
||||||
//clip.clone()
|
|
||||||
//} else {
|
|
||||||
//let clip: Arc<RwLock<MidiClip>> = Arc::new(RwLock::new(Default::default()));
|
|
||||||
//state.scenes()[*scene].clips[*track] = Some(clip.clone());
|
|
||||||
//clip
|
|
||||||
//}),
|
|
||||||
|
|
||||||
_ => return err!("not a clip: {word}")
|
|
||||||
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_opt_vec_opt_arc_rwlock_midiclip <'a> (_: &App, _: impl Language)
|
|
||||||
-> Perhaps<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>>
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A MIDI sequence.
|
/// A MIDI sequence.
|
||||||
|
|
@ -96,7 +77,32 @@ impl MidiClip {
|
||||||
clone.uuid = uuid::Uuid::new_v4();
|
clone.uuid = uuid::Uuid::new_v4();
|
||||||
clone
|
clone
|
||||||
}
|
}
|
||||||
pub fn toggle_loop (&mut self) { self.looped = !self.looped; }
|
/// Change the color of a clip, returning the previous color.
|
||||||
|
/// If value not provided, randomize.
|
||||||
|
pub fn set_color (&mut self, color: Option<ItemTheme>) -> ItemTheme {
|
||||||
|
let mut color = color.unwrap_or_else(||ItemTheme::random());
|
||||||
|
std::mem::swap(&mut color, &mut self.color);
|
||||||
|
color
|
||||||
|
}
|
||||||
|
/// Set loop mode for a clip, returning the previous loop state.
|
||||||
|
/// If value not provided, toggle.
|
||||||
|
pub fn toggle_loop (&mut self, looping: Option<bool>) -> bool {
|
||||||
|
match looping {
|
||||||
|
Some(true) => {
|
||||||
|
self.looped = true;
|
||||||
|
false
|
||||||
|
},
|
||||||
|
Some(false) => {
|
||||||
|
self.looped = false;
|
||||||
|
true
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.looped = !self.looped;
|
||||||
|
!self.looped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Add a [MidiMessage] at a given `pulse` position of this clip.
|
||||||
pub fn record_event (&mut self, pulse: usize, message: MidiMessage) {
|
pub fn record_event (&mut self, pulse: usize, message: MidiMessage) {
|
||||||
if pulse >= self.length { panic!("extend clip first") }
|
if pulse >= self.length { panic!("extend clip first") }
|
||||||
self.notes[pulse].push(message);
|
self.notes[pulse].push(message);
|
||||||
|
|
@ -110,40 +116,26 @@ impl MidiClip {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
/// Create a panic clip.
|
||||||
pub fn stop_all () -> Self {
|
pub fn stop_all () -> Self {
|
||||||
Self::new(
|
let color = Some(ItemColor::from_tui(Color::Rgb(32, 32, 32)).into());
|
||||||
"Stop",
|
Self::new("Stop", false, 1, Some(vec![vec![MIDI_PANIC]]), color)
|
||||||
false,
|
|
||||||
1,
|
|
||||||
Some(vec![vec![MidiMessage::Controller {
|
|
||||||
controller: 123.into(),
|
|
||||||
value: 0.into()
|
|
||||||
}]]),
|
|
||||||
Some(ItemColor::from_tui(Color::Rgb(32, 32, 32)).into())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MIDI_PANIC: MidiMessage = MidiMessage::Controller {
|
||||||
|
controller: u7::new(123), value: u7::new(0),
|
||||||
|
};
|
||||||
|
|
||||||
pub type MidiData = Vec<Vec<MidiMessage>>;
|
pub type MidiData = Vec<Vec<MidiMessage>>;
|
||||||
impl PartialEq for MidiClip { fn eq (&self, other: &Self) -> bool { self.uuid == other.uuid } }
|
impl PartialEq for MidiClip { fn eq (&self, other: &Self) -> bool { self.uuid == other.uuid } }
|
||||||
impl Eq for MidiClip {}
|
impl Eq for MidiClip {}
|
||||||
|
|
||||||
#[macro_export] macro_rules! has_clip {
|
impl HasMidiClip for Project {
|
||||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> { None }
|
||||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasMidiClip for $Struct $(<$($L),*$($T),*>)? {
|
|
||||||
fn clip (&$self) -> Option<Arc<RwLock<MidiClip>>> { $cb }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HasMidiClip {
|
|
||||||
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasMidiClip for App {
|
impl HasMidiClip for App {
|
||||||
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> { self.project.clip() }
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: HasMidiClip
|
impl<T: HasMidiClip
|
||||||
|
|
@ -156,24 +148,114 @@ pub trait MidiClipController: HasMidiClip
|
||||||
+ Namespace<Option<bool>>
|
+ Namespace<Option<bool>>
|
||||||
+ Namespace<Option<ItemTheme>>
|
+ Namespace<Option<ItemTheme>>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Create a clip at the current position if it does not already exist.
|
||||||
#[command(Upsert = "upsert")]
|
#[command(Upsert = "upsert")]
|
||||||
fn clip_upsert (&mut self) -> Perhaps<MidiClipCommand> {
|
fn clip_upsert (&mut self) -> Perhaps<MidiClipCommand> {
|
||||||
|
let clip = self.clip();
|
||||||
|
//let old = self.scenes[scene].clips[track].clone();
|
||||||
|
//self.scenes[scene].clips[track] = clip;
|
||||||
|
//old
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command(SetColor = "color")]
|
#[command(SetColor = "color")]
|
||||||
fn clip_set_color (&mut self, _color: Option<ItemTheme>) -> Perhaps<MidiClipCommand> {
|
fn clip_set_color (&mut self, color: Option<ItemTheme>) -> Perhaps<MidiClipCommand> {
|
||||||
//(SetColor [t: usize, s: usize, c: ItemTheme]
|
Ok(self.clip().map(|clip|MidiClipCommand::SetColor {
|
||||||
//clip.clip_set_color(t, s, c).map(|o|Self::SetColor(t, s, o)))));
|
color: Some(clip.write().set_color(color))
|
||||||
//("color" [a: usize, b: usize] Some(Self::SetColor(a.unwrap(), b.unwrap(), ItemTheme::random())))
|
}))
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggle looping for the active clip
|
||||||
#[command(SetLoop = "loop")]
|
#[command(SetLoop = "loop")]
|
||||||
fn clip_toggle_loop (&mut self, _looping: Option<bool>) -> Perhaps<MidiClipCommand> {
|
fn clip_toggle_loop (&mut self, looping: Option<bool>) -> Perhaps<MidiClipCommand> {
|
||||||
//(SetLoop [t: usize, s: usize, l: bool] cmd_todo!("\n\rtodo: {self:?}"))
|
Ok(self.clip().map(|clip|MidiClipCommand::SetLoop {
|
||||||
//("loop" [a: usize, b: usize, c: bool] Some(Self::SetLoop(a.unwrap(), b.unwrap(), c.unwrap())))
|
looping: Some(clip.write().toggle_loop(looping))
|
||||||
todo!()
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasClipsSize for App { fn clips_size (&self) -> &Sizer { &self.project.size_inner } }
|
||||||
|
impl HasClipsSize for Project { fn clips_size (&self) -> &Sizer { &self.size_inner } }
|
||||||
|
pub trait HasClipsSize {
|
||||||
|
/// Size of clips area.
|
||||||
|
fn clips_size (&self) -> &Sizer;
|
||||||
|
/// Draw content annotated with value of [Self::clips_size].
|
||||||
|
fn with_clips_size (&self, show: bool, content: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
|
let size = self.clips_size();
|
||||||
|
above(
|
||||||
|
when(show, fg(Green, east!(size.w() as usize, "x", size.h() as usize)).align_se()),
|
||||||
|
size.of(content.align_c().full_wh())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: TracksView + ScenesView + Send + Sync> ClipsView for T {}
|
||||||
|
|
||||||
|
pub trait ClipsView: TracksView + ScenesView {
|
||||||
|
|
||||||
|
/// Draw clips per scene
|
||||||
|
fn view_scenes_clips (&self) -> impl Draw<Tui> {
|
||||||
|
let select = self.selection();
|
||||||
|
let editor = self.editor();
|
||||||
|
let editing = self.is_editing();
|
||||||
|
self.with_clips_size(true, iter_east(move||self.tracks_with_sizes()
|
||||||
|
.map(move|(track_index, track, _, _)|iter_south(move||self.scenes_with_sizes()
|
||||||
|
.map(move|(scene_index, scene, _, _)|{
|
||||||
|
let (name, theme): (Arc<str>, ItemTheme) = view_scene_name_theme(scene, track_index);
|
||||||
|
let f = theme.lightest.term;
|
||||||
|
let (b, o) = view_scene_bg(theme, select, track_index, scene_index);
|
||||||
|
let is_selected = view_scene_sel(select, track_index, scene_index, editing);
|
||||||
|
below(
|
||||||
|
Outer(true, Style::default().fg(o)).full_wh(),
|
||||||
|
below(
|
||||||
|
below(
|
||||||
|
fg_bg(o, b, "".full_wh()),
|
||||||
|
fg_bg(f, b, bold(true, name)).align_nw().full_wh(),
|
||||||
|
),
|
||||||
|
when(is_selected, editor).full_wh()
|
||||||
|
).full_wh()
|
||||||
|
).exact_wh(
|
||||||
|
view_scene_w(track, select, track_index, editor.as_ref()),
|
||||||
|
view_scene_y(select, scene_index, editor.as_ref()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.exact_w(track.width as u16))
|
||||||
|
)).align_c()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_opt_arc_rwlock_midiclip <'a> (state: &App, src: impl Language)
|
||||||
|
-> Perhaps<Option<Arc<RwLock<MidiClip>>>>
|
||||||
|
{
|
||||||
|
eval_word(src, |word|Ok(match word {
|
||||||
|
|
||||||
|
":selected" if let Selection::TrackClip {
|
||||||
|
track, scene
|
||||||
|
} = state.selection() => {
|
||||||
|
state.scenes()[*scene].clips[*track].clone()
|
||||||
|
},
|
||||||
|
|
||||||
|
//":selected-or-create" if let Selection::TrackClip {
|
||||||
|
//track, scene
|
||||||
|
//} = state.selection() => Some(if let Some(Some(clip)) = state.scenes()[*scene].clips.get(*track) {
|
||||||
|
//clip.clone()
|
||||||
|
//} else {
|
||||||
|
//let clip: Arc<RwLock<MidiClip>> = Arc::new(RwLock::new(Default::default()));
|
||||||
|
//state.scenes()[*scene].clips[*track] = Some(clip.clone());
|
||||||
|
//clip
|
||||||
|
//}),
|
||||||
|
|
||||||
|
_ => return err!("not a clip: {word}")
|
||||||
|
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_opt_vec_opt_arc_rwlock_midiclip <'a> (_: &App, _: impl Language)
|
||||||
|
-> Perhaps<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>>
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,115 +1 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub type ClipPool = Vec<Arc<RwLock<MidiClip>>>;
|
|
||||||
|
|
||||||
pub trait HasClips {
|
|
||||||
fn clips <'a> (&'a self) -> RwLockReadGuard<'a, ClipPool>;
|
|
||||||
fn clips_mut <'a> (&'a self) -> RwLockWriteGuard<'a, ClipPool>;
|
|
||||||
fn add_clip (&self) -> (usize, Arc<RwLock<MidiClip>>) {
|
|
||||||
let clip = Arc::new(RwLock::new(MidiClip::new("Clip", true, 384, None, None)));
|
|
||||||
self.clips_mut().push(clip.clone());
|
|
||||||
(self.clips().len() - 1, clip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: Preserve the generic passthru syntax;
|
|
||||||
/// remove this macro (only used twice) and potentially the trait.
|
|
||||||
#[macro_export] macro_rules! impl_has_clips {
|
|
||||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
|
||||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasClips for $Struct $(<$($L),*$($T),*>)? {
|
|
||||||
fn clips <'a> (&'a $self) -> ::tengri::parking_lot::RwLockReadGuard<'a, ClipPool> {
|
|
||||||
$cb.try_read().unwrap()
|
|
||||||
}
|
|
||||||
fn clips_mut <'a> (&'a $self) -> ::tengri::parking_lot::RwLockWriteGuard<'a, ClipPool> {
|
|
||||||
$cb.try_write().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Project {
|
|
||||||
/// Toggle looping for the active clip
|
|
||||||
pub fn toggle_loop (&mut self) {
|
|
||||||
if let Some(clip) = self.selected_clip() {
|
|
||||||
clip.try_write().unwrap().toggle_loop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Put a clip in a slot
|
|
||||||
pub fn clip_put (
|
|
||||||
&mut self, track: usize, scene: usize, clip: Option<Arc<RwLock<MidiClip>>>
|
|
||||||
) -> Option<Arc<RwLock<MidiClip>>> {
|
|
||||||
let old = self.scenes[scene].clips[track].clone();
|
|
||||||
self.scenes[scene].clips[track] = clip;
|
|
||||||
old
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change the color of a clip, returning the previous one
|
|
||||||
pub fn clip_set_color (
|
|
||||||
&self, track: usize, scene: usize, color: ItemTheme
|
|
||||||
) -> Option<ItemTheme> {
|
|
||||||
self.scenes[scene].clips[track].as_ref().map(|clip|{
|
|
||||||
let mut clip = clip.try_write().unwrap();
|
|
||||||
let old = clip.color.clone();
|
|
||||||
clip.color = color.clone();
|
|
||||||
panic!("{color:?} {old:?}");
|
|
||||||
//old
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait HasClipsSize {
|
|
||||||
fn clips_size (&self) -> &Sizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasClipsSize for App {
|
|
||||||
fn clips_size (&self) -> &Sizer { &self.project.size_inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasClipsSize for Project {
|
|
||||||
fn clips_size (&self) -> &Sizer { &self.size_inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: TracksView + ScenesView + Send + Sync> ClipsView for T {}
|
|
||||||
|
|
||||||
pub trait ClipsView: TracksView + ScenesView {
|
|
||||||
|
|
||||||
/// Draw clips per scene
|
|
||||||
fn view_scenes_clips (&self) -> impl Draw<Tui> {
|
|
||||||
let select = self.selection();
|
|
||||||
let editor = self.editor();
|
|
||||||
let editing = self.is_editing();
|
|
||||||
with_clips_size(true, self.clips_size(), iter_east(move||self.tracks_with_sizes()
|
|
||||||
.map(move|(track_index, track, _, _)|iter_south(move||self.scenes_with_sizes()
|
|
||||||
.map(move|(scene_index, scene, _, _)|{
|
|
||||||
let (name, theme): (Arc<str>, ItemTheme) = view_scene_name_theme(scene, track_index);
|
|
||||||
let f = theme.lightest.term;
|
|
||||||
let (b, o) = view_scene_bg(theme, select, track_index, scene_index);
|
|
||||||
let is_selected = view_scene_sel(select, track_index, scene_index, editing);
|
|
||||||
below(
|
|
||||||
Outer(true, Style::default().fg(o)).full_wh(),
|
|
||||||
below(
|
|
||||||
below(
|
|
||||||
fg_bg(o, b, "".full_wh()),
|
|
||||||
fg_bg(f, b, bold(true, name)).align_nw().full_wh(),
|
|
||||||
),
|
|
||||||
when(is_selected, editor).full_wh()
|
|
||||||
).full_wh()
|
|
||||||
).exact_wh(
|
|
||||||
view_scene_w(track, select, track_index, editor.as_ref()),
|
|
||||||
view_scene_y(select, scene_index, editor.as_ref()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.exact_w(track.width as u16))
|
|
||||||
)).align_c()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_clips_size (show: bool, size: &Sizer, content: impl Draw<Tui>) -> impl Draw<Tui> {
|
|
||||||
above(
|
|
||||||
when(show, fg(Green, east!(size.w() as usize, "x", size.h() as usize)).align_se()),
|
|
||||||
size.of(content.align_c().full_wh())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
19
src/pool.rs
19
src/pool.rs
|
|
@ -19,6 +19,21 @@ use crate::*;
|
||||||
#[cfg(feature = "sampler")] pub samples: Arc<RwLock<Vec<Arc<RwLock<Sample>>>>>,
|
#[cfg(feature = "sampler")] pub samples: Arc<RwLock<Vec<Arc<RwLock<Sample>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasClips for Pool {
|
||||||
|
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||||
|
self.clips.read().get(self.clip_index()).map(|c|c.clone())
|
||||||
|
}
|
||||||
|
fn clip_mut (&self) -> &mut Option<Arc<RwLock<MidiClip>>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn clips <'a> (&'a self) -> RwLockReadGuard<'a, Clips> {
|
||||||
|
self.clips.read()
|
||||||
|
}
|
||||||
|
fn clips_mut <'a> (&'a self) -> RwLockWriteGuard<'a, Clips> {
|
||||||
|
self.clips.write()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Displays and edits clip length.
|
/// Displays and edits clip length.
|
||||||
#[derive(Clone, Debug, Default)] pub struct ClipLength {
|
#[derive(Clone, Debug, Default)] pub struct ClipLength {
|
||||||
/// Pulses per beat (quaver)
|
/// Pulses per beat (quaver)
|
||||||
|
|
@ -326,10 +341,6 @@ pub trait PoolController: HasPool
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
has_clip!(|self: Pool|self.clips().get(self.clip_index()).map(|c|c.clone()));
|
|
||||||
|
|
||||||
impl_has_clips!(|self: Pool|self.clips);
|
|
||||||
|
|
||||||
impl_from!(Pool: |clip:&Arc<RwLock<MidiClip>>|{
|
impl_from!(Pool: |clip:&Arc<RwLock<MidiClip>>|{
|
||||||
let model = Self::default();
|
let model = Self::default();
|
||||||
model.clips.try_write().unwrap().push(clip.clone());
|
model.clips.try_write().unwrap().push(clip.clone());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue