last small wave of 15 errors?

This commit is contained in:
🪞👃🪞 2025-05-14 17:15:27 +03:00
parent 4fe51b5267
commit 872c2d94d6
11 changed files with 181 additions and 189 deletions

View file

@ -30,9 +30,9 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
app.toggle_editor(Some(value));
Ok(None)
}
fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> {
Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme}))
}
//fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> {
//Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme}))
//}
fn enqueue (app: &mut App, clip: Option<Arc<RwLock<MidiClip>>>) -> Perhaps<Self> {
todo!()
}
@ -42,19 +42,18 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
fn zoom (app: &mut App, zoom: usize) -> Perhaps<Self> {
todo!()
}
fn launch (app: &mut App) -> Perhaps<Self> {
app.project.launch();
Ok(None)
}
//fn launch (app: &mut App) -> Perhaps<Self> {
//app.project.launch();
//Ok(None)
//}
fn select (app: &mut App, selection: Selection) -> Perhaps<Self> {
app.project.select(selection);
*app.project.selection_mut() = selection;
if let Some(ref mut editor) = app.editor {
editor.set_clip(match app.project.selected {
Some(Selection::TrackClip { track, scene })
if let Some(Some(Some(clip))) = app
editor.set_clip(match app.project.selection() {
Selection::TrackClip { track, scene } if let Some(Some(Some(clip))) = app
.project
.scenes.get(scene)
.map(|s|s.clips.get(track))
.scenes.get(*scene)
.map(|s|s.clips.get(*track))
=>
Some(clip),
_ =>
@ -79,14 +78,11 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
.transpose()?
.flatten())
}
fn arrange (app: &mut App, command: ArrangementCommand) -> Perhaps<Self> {
Ok(command.delegate(app, |command|Self::Arrange{command})?)
fn project (app: &mut App, command: ArrangementCommand) -> Perhaps<Self> {
Ok(command.delegate(&mut app.project, |command|Self::Project{command})?)
}
fn clock (app: &mut App, command: ClockCommand) -> Perhaps<Self> {
Ok(command.execute(&mut app.clock())?.map(|command|Self::Clock{command}))
}
fn device (app: &mut App, command: DeviceCommand) -> Perhaps<Self> {
Ok(command.delegate(app, |command|Self::Device{command})?)
Ok(command.execute(app.clock_mut())?.map(|command|Self::Clock{command}))
}
fn message (app: &mut App, command: MessageCommand) -> Perhaps<Self> {
Ok(command.delegate(app, |command|Self::Message{command})?)
@ -106,21 +102,20 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
})
}
fn pool (app: &mut App, command: PoolCommand) -> Perhaps<Self> {
Ok(if let Some(pool) = app.project.pool.as_mut() {
let undo = command.clone().delegate(pool, |command|AppCommand::Pool{command})?;
// update linked editor after pool action
app.editor.as_mut().map(|editor|match command {
// autoselect: automatically load selected clip in editor
PoolCommand::Select { .. } |
// autocolor: update color in all places simultaneously
PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } =>
editor.set_clip(pool.clip().as_ref()),
_ => {}
});
undo
} else {
None
})
let undo = command.clone().delegate(
&mut app.project.pool,
|command|AppCommand::Pool{command}
)?;
// update linked editor after pool action
app.editor.as_mut().map(|editor|match command {
// autoselect: automatically load selected clip in editor
PoolCommand::Select { .. } |
// autocolor: update color in all places simultaneously
PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } =>
editor.set_clip(app.project.pool.clip().as_ref()),
_ => {}
});
Ok(undo)
}
}
@ -138,7 +133,7 @@ impl<'state> Context<'state, MidiEditCommand> for App {
impl<'state> Context<'state, PoolCommand> for App {
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<PoolCommand> {
self.project.pool.map(|p|Context::get(p, iter)).flatten()
Context::get(&self.project.pool, iter)
}
}
@ -148,9 +143,15 @@ impl<'state> Context<'state, SamplerCommand> for App {
}
}
impl<'state> Context<'state, ArrangementCommand> for App {
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<ArrangementCommand> {
Context::get(&self.project, iter)
}
}
#[tengri_proc::command(App)] impl MessageCommand {
fn dismiss (app: &mut App) -> Perhaps<Self> {
app.message_dismiss();
app.dialog = None;
Ok(None)
}
}

View file

@ -1,11 +1,5 @@
use crate::*;
impl HasJack for App {
fn jack (&self) -> &Jack {
&self.jack
}
}
audio!(
|self: App, client, scope|{
let t0 = self.perf.get_t0();

View file

@ -28,12 +28,14 @@ pub struct App {
pub color: ItemTheme,
}
has!(Option<Selection>: |self: App|self.project.selection);
has!(Vec<JackMidiIn>: |self: App|self.project.midi_ins);
has!(Vec<JackMidiOut>: |self: App|self.project.midi_outs);
has!(Vec<Scene>: |self: App|self.project.scenes);
has!(Vec<Track>: |self: App|self.project.tracks);
has!(Clock: |self: App|self.project.clock);
has!(Jack: |self: App|self.jack);
has!(Clock: |self: App|self.project.clock);
has!(Selection: |self: App|self.project.selection);
has!(Vec<JackMidiIn>: |self: App|self.project.midi_ins);
has!(Vec<JackMidiOut>: |self: App|self.project.midi_outs);
has!(Vec<Scene>: |self: App|self.project.scenes);
has!(Vec<Track>: |self: App|self.project.tracks);
has_size!(<TuiOut>|self: App|&self.size);
has_clips!(|self: App|self.project.pool.clips);
has_editor!(|self: App|{
@ -46,24 +48,28 @@ has_editor!(|self: App|{
(5 + (time_len / time_zoom)).min(size.saturating_sub(20)).max(16)
};
editor_h = 15;
is_editing = self.editing.load(Relaxed);
is_editing = self.editor.is_some();
});
impl App {
pub fn toggle_dialog (&mut self, dialog: Option<Dialog>) {
self.dialog = if self.dialog == dialog {
None
} else {
dialog
}
pub fn toggle_dialog (&mut self, mut dialog: Option<Dialog>) -> Option<Dialog> {
std::mem::swap(&mut self.dialog, &mut dialog);
dialog
}
pub fn toggle_editor (&mut self, value: Option<bool>) {
self.editing.store(value.unwrap_or_else(||!self.is_editing()), Relaxed);
self.arranger.map(|arranger|if value {
arranger.clip_auto_create();
//FIXME: self.editing.store(value.unwrap_or_else(||!self.is_editing()), Relaxed);
let value = value.unwrap_or_else(||!self.editor.is_some());
if value {
self.clip_auto_create();
} else {
arranger.clip_auto_remove();
});
self.clip_auto_remove();
}
}
pub fn browser (&self) -> Option<&Browser> {
self.dialog.as_ref().and_then(|dialog|match dialog {
Dialog::Save(b) | Dialog::Load(b) => Some(b),
_ => None
})
}
pub(crate) fn device_pick (&mut self, index: usize) {
self.dialog = Some(Dialog::Device(index));
@ -85,15 +91,14 @@ impl App {
todo!();
Ok(())
}
fn device_add_sampler (&mut self, jack: &Jack) -> Usually<usize> {
let name = jack.with_client(|c|c.name().to_string());
let midi = self.track().expect("no active track").sequencer.midi_outs[0].name();
fn device_add_sampler (&mut self) -> Usually<()> {
let name = self.jack.with_client(|c|c.name().to_string());
let midi = self.project.track().expect("no active track").sequencer.midi_outs[0].name();
let track = self.track().expect("no active track");
let port = format!("{}/Sampler", &track.name);
let connect = PortConnect::exact(format!("{name}:{midi}"));
let sampler = if let Ok(sampler) = Sampler::new(
jack,
&format!("{}/Sampler", Has::<Track>::get(self).name),
&[PortConnect::exact(format!("{name}:{midi}"))],
&[&[], &[]],
&[&[], &[]]
&self.jack, &port, &[connect], &[&[], &[]], &[&[], &[]]
) {
self.dialog = None;
Device::Sampler(sampler)
@ -101,22 +106,23 @@ impl App {
self.dialog = Some(Dialog::Message(Message::FailedToAddDevice));
return Err("failed to add device".into())
};
Has::<Track>::get_mut(self).expect("no active track").devices.push(sampler);
let track = self.track_mut().expect("no active track");
track.devices.push(sampler);
Ok(())
}
// Create new clip in pool when entering empty cell
fn clip_auto_create (&mut self) -> Option<Arc<RwLock<MidiClip>>> {
if let Some(Selection::TrackClip { track, scene }) = self.get()
&& let Some(scene) = Has::<Vec<Scene>>::get_mut(self).get_mut(scene)
if let Selection::TrackClip { track, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& let Some(slot) = scene.clips.get_mut(track)
&& slot.is_none()
&& let Some(track) = Has::<Vec<Track>>::get_mut(self).get_mut(track)
&& let Some(track) = self.project.tracks.get_mut(track)
{
let (index, mut clip) = self.arranger.pool.add_new_clip();
let (index, mut clip) = self.project.pool.add_new_clip();
// autocolor: new clip colors from scene and track color
let color = track.color.base.mix(scene.color.base, 0.5);
clip.write().unwrap().color = ItemColor::random_near(color, 0.2).into();
if let Some(ref mut editor) = Has::<Option<MidiEditor>>::get_mut(self) {
if let Some(ref mut editor) = self.editor {
editor.set_clip(Some(&clip));
}
*slot = Some(clip.clone());
@ -125,37 +131,24 @@ impl App {
None
}
}
}
#[cfg(all(feature = "pool", feature = "editor"))]
pub trait AutoRemove:
Has<Vec<Scene>> +
Has<Vec<Track>> +
Has<Option<MidiEditor>> +
Has<Option<Selection>> +
Has<Option<Pool>> +
Send + Sync
{
// Remove clip from arrangement when exiting empty clip editor
fn clip_auto_remove (&mut self) {
if let Some(ref mut pool) = Has::<Option<Pool>>::get(self)
&& let Some(Selection::TrackClip { track, scene }) = self.get()
&& let Some(scene) = Has::<Vec<Scene>>::get_mut(self).get_mut(*scene)
&& let Some(slot) = scene.clips.get_mut(*track)
&& let Some(clip) = slot.as_mut()
if let Selection::TrackClip { track, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& let Some(slot) = scene.clips.get_mut(track)
&& let Some(clip) = slot.as_mut()
{
let mut swapped = None;
if clip.read().unwrap().count_midi_messages() == 0 {
std::mem::swap(&mut swapped, slot);
}
if let Some(clip) = swapped {
pool.delete_clip(&clip.read().unwrap());
self.project.pool.delete_clip(&clip.read().unwrap());
}
}
}
}
/// Various possible dialog overlays
#[derive(Clone, Debug)]
pub enum Dialog {
@ -197,7 +190,7 @@ impl App {
matches!(self.dialog, Some(Dialog::Device(..)))
}
fn focus_browser (&self) -> bool {
self.browser.is_visible
self.browser().is_some()
}
fn focus_clip (&self) -> bool {
!self.is_editing() && self.selection().is_clip()
@ -212,16 +205,16 @@ impl App {
!self.is_editing() && self.selection().is_mix()
}
fn focus_pool_import (&self) -> bool {
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Import(..)))
matches!(self.project.pool.mode, Some(PoolMode::Import(..)))
}
fn focus_pool_export (&self) -> bool {
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Export(..)))
matches!(self.project.pool.mode, Some(PoolMode::Export(..)))
}
fn focus_pool_rename (&self) -> bool {
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Rename(..)))
matches!(self.project.pool.mode, Some(PoolMode::Rename(..)))
}
fn focus_pool_length (&self) -> bool {
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Length(..)))
matches!(self.project.pool.mode, Some(PoolMode::Length(..)))
}
fn dialog_device (&self) -> Dialog {
Dialog::Device(0) // TODO
@ -239,10 +232,10 @@ impl App {
Dialog::Menu
}
fn dialog_save (&self) -> Dialog {
Dialog::Save
Dialog::Save(Default::default())
}
fn dialog_load (&self) -> Dialog {
Dialog::Load
Dialog::Load(Default::default())
}
fn dialog_options (&self) -> Dialog {
Dialog::Options
@ -251,13 +244,13 @@ impl App {
Some((self.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8).into())
}
fn scene_count (&self) -> usize {
self.scenes.len()
self.scenes().len()
}
fn scene_selection (&self) -> Option<usize> {
self.selection().scene()
}
fn track_count (&self) -> usize {
self.tracks.len()
self.tracks().len()
}
fn track_selection (&self) -> Option<usize> {
self.selection().track()
@ -279,7 +272,7 @@ impl App {
}
fn clip_selection (&self) -> Option<Arc<RwLock<MidiClip>>> {
match self.selection() {
Selection::TrackClip { track, scene } => self.scenes()[scene].clips[track].clone(),
Selection::TrackClip { track, scene } => self.scenes()[*scene].clips[*track].clone(),
_ => None
}
}

View file

@ -17,7 +17,7 @@ impl App {
pub fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
self.update_clock();
let cache = self.view_cache.read().unwrap();
view_status(self.project.selected.map(|x|x.describe(self.tracks(), self.scenes())),
view_status(Some(self.project.selection.describe(self.tracks(), self.scenes())),
cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone())
}
pub fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {

View file

@ -6,27 +6,28 @@ impl Arrangement {
fn _todo_arc_str_stub_ (&self) -> Arc<str> { todo!() }
fn _todo_item_theme_stub (&self) -> ItemTheme { todo!() }
fn _todo_opt_item_theme_stub (&self) -> Option<ItemTheme> { todo!() }
fn _todo_opt_selection_ (&self) -> Option<Selection> { todo!() }
fn select_nothing (&self) -> Selection {
Selection::Nothing
}
}
#[tengri_proc::command(Arrangement)]
impl ArrangementCommand {
/// Set the selection
fn select (arranger: &mut Arrangement, s: Option<Selection>) -> Perhaps<Self> {
arranger.selected = s;
fn select (arranger: &mut Arrangement, s: Selection) -> Perhaps<Self> {
*arranger.selection_mut() = s;
Ok(None)
}
/// Launch a clip or scene
fn launch (arranger: &mut Arrangement) -> Perhaps<Self> {
use Selection::*;
match arranger.selected {
Some(Track(t)) => {
match *arranger.selection() {
Selection::Track(t) => {
arranger.tracks[t].sequencer.enqueue_next(None)
},
Some(TrackClip { track, scene }) => {
Selection::TrackClip { track, scene } => {
arranger.tracks[track].sequencer.enqueue_next(arranger.scenes[scene].clips[track].as_ref())
},
Some(Scene(s)) => {
Selection::Scene(s) => {
for t in 0..arranger.tracks.len() {
arranger.tracks[t].sequencer.enqueue_next(arranger.scenes[s].clips[t].as_ref())
}
@ -37,49 +38,44 @@ impl ArrangementCommand {
}
/// Set the color of the selected entity
fn set_color (arranger: &mut Arrangement, palette: Option<ItemTheme>) -> Perhaps<Self> {
use Selection::*;
let palette = palette.unwrap_or_else(||ItemTheme::random());
Ok(Some(Self::SetColor { palette: match arranger.selected {
Some(Mix) => {
let old = arranger.color;
arranger.color = palette;
Some(old)
let mut palette = palette.unwrap_or_else(||ItemTheme::random());
let selection = *arranger.selection();
Ok(Some(Self::SetColor { palette: Some(match selection {
Selection::Mix => {
std::mem::swap(&mut palette, &mut arranger.color);
palette
},
Some(Scene(s)) => {
let old = arranger.scenes[s].color;
arranger.scenes[s].color = palette;
Some(old)
Selection::Scene(s) => {
std::mem::swap(&mut palette, &mut arranger.scenes[s].color);
palette
}
Some(Track(t)) => {
let old = arranger.tracks[t].color;
arranger.tracks[t].color = palette;
Some(old)
Selection::Track(t) => {
std::mem::swap(&mut palette, &mut arranger.tracks[t].color);
palette
}
Some(TrackClip { track, scene }) => {
Selection::TrackClip { track, scene } => {
if let Some(ref clip) = arranger.scenes[scene].clips[track] {
let mut clip = clip.write().unwrap();
let old = clip.color;
clip.color = palette;
Some(old)
std::mem::swap(&mut palette, &mut clip.color);
palette
} else {
None
return Ok(None)
}
},
_ => todo!()
} }))
}) }))
}
fn track (arranger: &mut Arrangement, track: TrackCommand) -> Perhaps<Self> {
todo!("delegate")
}
fn track_add (arranger: &mut Arrangement) -> Perhaps<Self> {
let index = arranger.track_add(None, None, &[], &[])?.0;
arranger.selected = match arranger.selected {
Some(Selection::Track(_)) =>
Some(Selection::Track(index)),
Some(Selection::TrackClip { track, scene }) =>
Some(Selection::TrackClip { track: index, scene }),
_ => arranger.selected
*arranger.selection_mut() = match arranger.selection() {
Selection::Track(_) => Selection::Track(index),
Selection::TrackClip { track, scene } => Selection::TrackClip {
track: index, scene: *scene
},
_ => *arranger.selection()
};
Ok(Some(Self::TrackDelete { index }))
}
@ -135,12 +131,13 @@ impl ArrangementCommand {
}
fn scene_add (arranger: &mut Arrangement) -> Perhaps<Self> {
let index = arranger.scene_add(None, None)?.0;
arranger.selected = match arranger.selected {
Some(Selection::Scene(_)) =>
Some(Selection::Scene(index)),
Some(Selection::TrackClip { track, scene }) =>
Some(Selection::TrackClip { track, scene: index }),
_ => arranger.selected
*arranger.selection_mut() = match arranger.selection() {
Selection::Scene(_) => Selection::Scene(index),
Selection::TrackClip { track, scene } => Selection::TrackClip {
track: *track,
scene: index
},
_ => *arranger.selection()
};
Ok(None) // TODO
}

View file

@ -33,7 +33,7 @@ pub struct Arrangement {
/// Scroll offset of scenes
pub scene_scroll: usize,
/// Selected UI element
pub selected: Option<Selection>,
pub selection: Selection,
/// Contains a render of the project arrangement, redrawn on update.
/// TODO rename to "render_cache" or smth
pub arranger: Arc<RwLock<Buffer>>,
@ -43,13 +43,13 @@ pub struct Arrangement {
pub pool: Pool,
}
has!(Option<Selection>: |self: Arrangement|self.selected);
has!(Vec<JackMidiIn>: |self: Arrangement|self.midi_ins);
has!(Vec<JackMidiOut>: |self: Arrangement|self.midi_outs);
has!(Vec<Scene>: |self: Arrangement|self.scenes);
has!(Vec<Track>: |self: Arrangement|self.tracks);
has!(Jack: |self: Arrangement|self.jack);
has!(Clock: |self: Arrangement|self.clock);
has!(Jack: |self: Arrangement|self.jack);
has!(Clock: |self: Arrangement|self.clock);
has!(Selection: |self: Arrangement|self.selection);
has!(Vec<JackMidiIn>: |self: Arrangement|self.midi_ins);
has!(Vec<JackMidiOut>: |self: Arrangement|self.midi_outs);
has!(Vec<Scene>: |self: Arrangement|self.scenes);
has!(Vec<Track>: |self: Arrangement|self.tracks);
impl Arrangement {
/// Width of display
@ -62,7 +62,7 @@ impl Arrangement {
}
/// Width taken by all tracks.
pub fn w_tracks (&self) -> u16 {
self.tracks_with_sizes(&self.selected, None).last()
self.tracks_with_sizes(&self.selection(), None).last()
.map(|(_, _, _, x)|x as u16).unwrap_or(0)
}
/// Width available to display tracks.
@ -90,18 +90,12 @@ impl Arrangement {
}
/// Height taken by all scenes.
pub fn h_scenes (&self, is_editing: bool) -> u16 {
let (selected_track, selected_scene) = match Has::<Option<Selection>>::get(self) {
Some(Selection::Track(t)) => (Some(*t), None),
Some(Selection::Scene(s)) => (None, Some(*s)),
Some(Selection::TrackClip { track, scene }) => (Some(*track), Some(*scene)),
_ => (None, None)
};
self.scenes_with_sizes(
is_editing,
ArrangerView::H_SCENE,
ArrangerView::H_EDITOR,
selected_track,
selected_scene
self.selection().track(),
self.selection().scene(),
)
.last()
.map(|(_, _, _, y)|y as u16).unwrap_or(0)
@ -121,27 +115,27 @@ impl Arrangement {
}
/// Get the active track
fn get_track (&self) -> Option<&Track> {
let index = self.selection()?.track()?;
let index = self.selection().track()?;
Has::<Vec<Track>>::get(self).get(index)
}
/// Get a mutable reference to the active track
fn get_track_mut (&mut self) -> Option<&mut Track> {
let index = self.selection()?.track()?;
let index = self.selection().track()?;
Has::<Vec<Track>>::get_mut(self).get_mut(index)
}
/// Get the active scene
fn get_scene (&self) -> Option<&Scene> {
let index = self.selection()?.scene()?;
let index = self.selection().scene()?;
Has::<Vec<Scene>>::get(self).get(index)
}
/// Get a mutable reference to the active scene
fn get_scene_mut (&mut self) -> Option<&mut Scene> {
let index = self.selection()?.scene()?;
let index = self.selection().scene()?;
Has::<Vec<Scene>>::get_mut(self).get_mut(index)
}
/// Get the active clip
fn get_clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
self.get_scene()?.clips.get(self.selection()?.track()?)?.clone()
self.get_scene()?.clips.get(self.selection().track()?)?.clone()
}
/// Put a clip in a slot
pub fn clip_put (

View file

@ -1,19 +1,16 @@
use crate::*;
impl<T: Has<Option<Selection>>> HasSelection for T {}
impl<T: Has<Selection>> HasSelection for T {}
pub trait HasSelection: Has<Option<Selection>> {
fn selection (&self) -> Option<&Selection> {
self.get().as_ref()
pub trait HasSelection: Has<Selection> {
fn selection (&self) -> &Selection {
self.get()
}
fn selection_mut (&mut self) -> &mut Option<Selection> {
fn selection_mut (&mut self) -> &mut Selection {
self.get_mut()
}
}
impl Arrangement {
}
/// Represents the current user selection in the arranger
#[derive(PartialEq, Clone, Copy, Debug, Default)]
pub enum Selection {

View file

@ -149,13 +149,27 @@ impl Track {
}
}
impl<T: Has<Option<Track>> + Send + Sync> HasTrack for T {}
pub trait HasTrack {
fn track (&self) -> Option<&Track>;
fn track_mut (&mut self) -> Option<&mut Track>;
}
pub trait HasTrack: Has<Option<Track>> + Send + Sync {
//impl<T: Has<Option<Track>>> HasTrack for T {
//fn track (&self) -> Option<&Track> {
//self.get().as_ref()
//}
//fn track_mut (&mut self) -> Option<&mut Track> {
//self.get_mut().as_mut()
//}
//}
impl<T: Has<Vec<Track>> + Has<Selection>> HasTrack for T {
fn track (&self) -> Option<&Track> {
Has::<Option<Track>>::get(self).as_ref()
let index = Has::<Selection>::get(self).track()?;
Has::<Vec<Track>>::get(self).get(index)
}
fn track_mut (&mut self) -> Option<&mut Track> {
Has::<Option<Track>>::get_mut(self).as_mut()
let index = Has::<Selection>::get(self).track()?;
Has::<Vec<Track>>::get_mut(self).get_mut(index)
}
}

View file

@ -47,11 +47,11 @@ pub trait HasTracks: Has<Vec<Track>> + Send + Sync {
/// Iterate over tracks with their corresponding sizes.
fn tracks_with_sizes (
&self,
selection: &Option<Selection>,
selection: &Selection,
editor_width: Option<usize>
) -> impl TracksSizes<'_> {
let mut x = 0;
let active_track = if let Some(width) = editor_width && let Some(selection) = selection {
let active_track = if let Some(width) = editor_width {
selection.track()
} else {
None
@ -74,7 +74,10 @@ impl<'a> ArrangerView<'a> {
-> impl TracksSizes<'a>
{
self.arrangement
.tracks_with_sizes(&self.arrangement.selected, self.is_editing.then_some(20/*FIXME*/))
.tracks_with_sizes(
&self.arrangement.selection(),
self.is_editing.then_some(20/*FIXME*/)
)
.map_while(move|(t, track, x1, x2)|{
(self.width_mid > x2 as u16).then_some((t, track, x1, x2))
})

View file

@ -35,7 +35,6 @@ impl<'a> ArrangerView<'a> {
editor: Option<&'a MidiEditor>
) -> Self {
let is_editing = editor.is_some();
let selected = arrangement.selected;
let h_tracks_area = arrangement.h_tracks_area();
let h_scenes_area = arrangement.h_scenes_area();
let h_scenes = arrangement.h_scenes(is_editing);
@ -54,7 +53,7 @@ impl<'a> ArrangerView<'a> {
outputs_count: arrangement.midi_outs.len(),
scenes_height: h_scenes_area,
scene_selected: selected.map(|s|s.scene()).flatten(),
scene_selected: arrangement.selection().scene(),
scene_count: arrangement.scenes.len(),
scene_last: arrangement.scenes.len().saturating_sub(1),
scene_scroll: Fill::y(Fixed::x(1, ScrollbarV {
@ -65,7 +64,7 @@ impl<'a> ArrangerView<'a> {
tracks_height: h_tracks_area,
track_count: arrangement.tracks.len(),
track_selected: selected.map(|s|s.track()).flatten(),
track_selected: arrangement.selection().track(),
track_scroll: Fill::x(Fixed::y(1, ScrollbarH {
offset: arrangement.track_scroll,
length: h_tracks_area as usize,
@ -160,9 +159,9 @@ impl<'a> ArrangerView<'a> {
track_selected, is_editing, ..
} = self;
let selection = Has::<Option<Selection>>::get(self.arrangement);
let selected_track = selection.map(|s|s.track()).flatten();
let selected_scene = selection.map(|s|s.scene()).flatten();
let selection = Has::<Selection>::get(self.arrangement);
let selected_track = selection.track();
let selected_scene = selection.scene();
Tryptich::center(*scenes_height)
.left(*width_side, Map::new(

View file

@ -3,7 +3,7 @@ use std::path::PathBuf;
use std::ffi::OsString;
/// Browses for phrase to import/export
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct Browser {
pub cwd: PathBuf,
pub dirs: Vec<(OsString, String)>,