public virtual void ShiftTracks(int delta, GuiLabs.Undo.ActionManager am = null) { var oldIndices = Tracks.Select(t => t.GetIndex()).ToList(); var newIndices = oldIndices.Select(i => i + delta).ToList(); if (newIndices.Any(i => i < 0 || i >= timeline.Tracks.Count)) { throw new ArgumentException("shifting tracks would move them out of range", "delta"); } // runtime complexity is horrendeous, but we don't have that many tracks ... foreach (int i in newIndices) { if (!oldIndices.Contains(i)) { am.RecordAdd(Tracks, timeline.Tracks[i]); } } foreach (int i in oldIndices) { if (!newIndices.Contains(i)) { am.RecordRemove(Tracks, timeline.Tracks[i]); } } }
public override void ExtendToTrack(Track fromTrack, Track toTrack, GuiLabs.Undo.ActionManager am = null) { foreach (var child in _children.Where(b => b.Tracks.Contains(fromTrack))) { am.RecordAdd(child.Tracks, toTrack); } RecalcTracks(); }
public virtual void ExtendToTrack(Track fromTrack, Track toTrack, GuiLabs.Undo.ActionManager am = null) { if (Tracks.Contains(toTrack)) { throw new InvalidOperationException("block is already part of track"); } //Tracks.Add(toTrack); am.RecordAdd(Tracks, toTrack); }
public override void ShiftTracks(int delta, GuiLabs.Undo.ActionManager am = null) { am.RecordAction(() => { }, RecalcTracks); foreach (var child in Children) { child.ShiftTracks(delta, am); } RecalcTracks(); }
public virtual bool RemoveFromTrack(Track track, GuiLabs.Undo.ActionManager am = null) { if (Tracks.Count <= 1) { return(false); } if (!Tracks.Contains(track)) { throw new InvalidOperationException("block is not part of track"); } am.RecordRemove(Tracks, track); return(true); }
public override bool RemoveFromTrack(Track track, GuiLabs.Undo.ActionManager am = null) { if (base.RemoveFromTrack(track, am)) { foreach (var child in _children.Where(b => b.Tracks.Contains(track)).Reverse().ToArray()) { if (child.Tracks.Count > 1) { am.RecordRemove(child.Tracks, track); } else { am.RecordRemove(_children, child); } } // since the base method already removed the track from the group block, // this call should in theory be redundant RecalcTracks(); return(true); } return(false); }
public SequencerViewModel(Timeline model) { this.model = model; ActionManager = new GuiLabs.Undo.ActionManager(); SelectedBlocks = new ObservableCollection <BlockViewModel>(); SelectionData = new SelectionProperties(this); Tracks = model.Tracks.Select(g => new TrackViewModel(this, g)); MusicSegments = model.MusicSegments.Select(seg => new MusicSegmentViewModel(this, seg)); AllBlocks = model.Blocks.Select(b => BlockViewModel.FromModel(this, b)); if (Tracks.Count > 0) { SelectedTrack = Tracks[0]; } ActiveMusicSegment = MusicSegments[model.DefaultMusicSegment.GetIndex()]; Playback = new PlaybackViewModel(this); Visualization = new VisualizationViewModel(this); Notes = new NotesViewModel(this); if (model.MusicFileName != null) { Playback.LoadFileAsync(model.MusicFileName).Forget(); } Action <BlockViewModel> fn_SubscribeToBlock = bvm => ForwardPropertyEvents(nameof(bvm.EndTimeOccupied), bvm, nameof(TimelineLength)); AllBlocks.ToList().ForEach(fn_SubscribeToBlock); AllBlocks.CollectionChanged += (_, e) => { if (e.NewItems != null) { e.NewItems.Cast <BlockViewModel>().ToList().ForEach(fn_SubscribeToBlock); } Notify(nameof(TimelineLength)); }; ForwardPropertyEvents(nameof(PipetteTarget), this, nameof(IsPipetteActive)); ForwardPropertyEvents(nameof(CursorPosition), this, nameof(CursorPixelPosition), nameof(CursorPixelPositionOnViewport)); ForwardPropertyEvents(nameof(TimePixelScale), this, nameof(CursorPixelPosition), nameof(CursorPixelPositionOnViewport), nameof(CurrentViewLeftPositionTime), nameof(CurrentViewRightPositionTime), nameof(TimelineWidth), nameof(GridInterval)); ForwardPropertyEvents(nameof(ActiveMusicSegment), this, nameof(GridInterval)); ForwardPropertyEvents(nameof(Playback.MusicDuration), Playback, nameof(TimelineLength)); ForwardPropertyEvents(nameof(TimelineLength), this, nameof(TimelineWidth)); ForwardCollectionEvents(SelectedBlocks, nameof(CanConvertToColor), nameof(CanConvertToRamp), nameof(CanConvertToAutoDeduced), nameof(ConvertAutoDeduceGestureText)); Tracks.CollectionChanged += (_, e) => { foreach (var b in AllBlocks) { b.OnTracksCollectionChanged(); } }; // Disable pipette whenever the selection is modified. SelectedBlocks.CollectionChanged += (_, __) => PipetteTarget = null; }