using NAudio.Midi; using QuikDawEditor.SampleProviders; using static QuikDawEditor.EDITING.AudioMethods; namespace QuikDawEditor { public partial class TrackControl : UserControl { public TrackControl() { InitializeComponent(); } Track thisTrack { get { return (Track)this.DataContext; } } bool MouseDownOnVolSlider = false; bool MouseDownOnPanSlider = false; private void PanSlider_MouseDoubleClick(object sender, MouseButtonEventArgs e) { PanSlider.Value = 0; } private void RTextBlock_MouseDown(object sender, MouseButtonEventArgs e) { PanSlider.Value = 1; } private void LTextBlock_MouseDown(object sender, MouseButtonEventArgs e) { PanSlider.Value = -1; } float preslidePan = -1; private void PanSlider_PreviewMouseDown(object sender, MouseButtonEventArgs e) { MouseDownOnPanSlider = true; preslidePan = thisTrack.Pan; } private void PanSlider_PreviewMouseUp(object sender, MouseButtonEventArgs e) { MouseDownOnPanSlider = false; undoActions.Add(new TrackPanChangeUndo(thisTrack.UndoTrackID, preslidePan)); } private void PanSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (MouseDownOnPanSlider) editingProject.NeedsSaving = true; } float preslideVolume = -1; private void VolSlider_PreviewMouseDown(object sender, MouseButtonEventArgs e) { MouseDownOnVolSlider = true; preslideVolume = thisTrack.Volume; } private void VolSlider_PreviewMouseUp(object sender, MouseButtonEventArgs e) { MouseDownOnVolSlider = false; undoActions.Add(new TrackVolumeChangeUndo(thisTrack.UndoTrackID, preslideVolume)); } private void VolSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (MouseDownOnVolSlider) editingProject.NeedsSaving = true; } private void SoloBut_Click(object sender, RoutedEventArgs e) { undoActions.Add(new TrackSoloToggleUndo(thisTrack.UndoTrackID)); thisTrack.ToggleSolo(); editingProject.NeedsSaving = true; } private void MuteBut_Click(object sender, RoutedEventArgs e) { undoActions.Add(new TrackMuteToggleUndo(thisTrack.UndoTrackID)); thisTrack.IsMuted = !thisTrack.IsMuted; thisTrack.ResetAllSubClips(thisTrack, projPlayer.CurrentPlayingPosMS); editingProject.NeedsSaving = true; } private void DeleteTrackMenuItem_Click(object sender, RoutedEventArgs e) { if (MessageBox.Show("Delete this track?:\nTrack name: " + thisTrack.TrackName, "Delete track", MessageBoxButton.YesNo) == MessageBoxResult.No) return; if (thisTrack.Clips.Count > 0) if (MessageBox.Show("This track contains clips (not empty). Delete track and all clips in it?", "Delete track with clips", MessageBoxButton.YesNo) == MessageBoxResult.No) return; try { TrackSampleProvider thisTSP = thisTrack.myTrackSampleProvider; for (int clipno = thisTrack.Clips.Count - 1; clipno > -1; clipno -= 1) { thisTrack.Clips[clipno].myClipSampleProvider?.Dispose(); thisTrack.Clips[clipno].myClipSampleProvider = null; } } catch (Exception ex) { Debug.WriteLine("Error deleting track: \n" + ex.Message); } undoActions.Add(new TrackDeleteUndo(thisTrack.GetTrackIndex, GetJsonForTrack(thisTrack), thisTrack.parentTrack == null ? "" : thisTrack.parentTrack.UndoTrackID)); if (thisTrack.parentTrack == null) editingProject.Tracks.Remove(thisTrack); else thisTrack.parentTrack.SubTracks.Remove(thisTrack); editingProject.UpdateAllClips(editingProject.Tracks); DeleteOrphanAudio(); editingProject.NeedsSaving = true; } private void HideTrackMenuItem_Click(object sender, RoutedEventArgs e) { undoActions.Add(new TrackHideToggleUndo(thisTrack.UndoTrackID)); thisTrack.IsTrackCollapsed = true; editingProject.hiddenTracks.Add(thisTrack); editingProject.NeedsSaving = true; } private void RenameTrackMenuItem_Click(object sender, RoutedEventArgs e) { RenameTrack(); } private void ToggleTrackScaleBut_Click(object sender, RoutedEventArgs e) { thisTrack.TrackYScale = thisTrack.TrackYScale == 1 ? 0.7 : 1; editingProject.NeedsSaving = true; } private void ClearClipsTrackMenuItem_Click(object sender, RoutedEventArgs e) { if (MessageBox.Show("Delete all clips on this track?:\nClip count: " + thisTrack.Clips.Count.ToString(), "Clear all clips", MessageBoxButton.YesNo) == MessageBoxResult.No) return; thisTrack.Clips.Clear(); editingProject.NeedsSaving = true; } private void ToggleAutomationLanesBut_Click(object sender, RoutedEventArgs e) { thisTrack.AutomationLanesVisible = !thisTrack.AutomationLanesVisible; undoActions.Add(new AutomationLanesCollapseToggleUndo(thisTrack.UndoTrackID)); } private void AutomationLaneCB_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (AutomationLanesCB.SelectedIndex == -1) return; if (!IsUndoing) { if (e.RemovedItems.Count > 0) { AutomationLane unselectedAC = (AutomationLane)e.RemovedItems[0]; undoActions.Add(new SelectedAutomationLaneChangeUndo(thisTrack.UndoTrackID, thisTrack.AutomationLanes.IndexOf(unselectedAC))); } } } private void VolSlider_MouseDoubleClick(object sender, MouseButtonEventArgs e) { VolSlider.Value = 0; } private void TrackNameTB_MouseDown(object sender, MouseButtonEventArgs e) { if (e.ClickCount == 2) { RenameTrack(); return; } } private void RenameTrack() { InputBox inpbox = new InputBox("Enter new track name", thisTrack.TrackName); //inpbox.Top = Math.Min(50 + 80 * this.Transl thisTrack.trackIndex, SystemParameters.WorkArea.Height - 100); //inpbox.Top = Math.Min(50 + TranslatePoint(new Point(this.Margin.Left, this.Margin.Top), 80 * this.Transl thisTrack.trackIndex, SystemParameters.WorkArea.Height - 100); inpbox.ShowDialog(); if (inpbox.Result == "Cancel") return; undoActions.Add(new TrackRenameUndo(thisTrack.UndoTrackID, thisTrack.TrackName)); thisTrack.TrackName = inpbox.TextBoxText; editingProject.NeedsSaving = true; } private void fxBut_Click(object sender, RoutedEventArgs e) { if (thisTrack.fxWindow != null && thisTrack.fxWindow.IsVisible) { thisTrack.fxWindow.Activate(); return; } thisTrack.fxWindow = new VstFxWindow() { Owner = Application.Current.MainWindow }; thisTrack.fxWindow.DataContext = thisTrack; thisTrack.fxWindow.SelectedVstsLV.ItemsSource = thisTrack.TrackEffectVsts; thisTrack.fxWindow.Left = thisTrack.FxWinLocation.int1; thisTrack.fxWindow.Top = thisTrack.FxWinLocation.int2; thisTrack.fxWindow.Show(); } private void MidiTrackInstrumentBut_Click(object sender, RoutedEventArgs e) { if (thisTrack.trackType != TrackType.Midi) return; if (thisTrack.vstiWin != null && thisTrack.vstiWin.IsVisible) { thisTrack.vstiWin.Activate(); return; } thisTrack.vstiWin = new VstiWindow() { Owner = (EditorWindow)Application.Current.MainWindow, ShowInTaskbar = false}; thisTrack.vstiWin.DataContext = thisTrack; thisTrack.vstiWin.Left = thisTrack.FxWinLocation.int1; thisTrack.vstiWin.Top = thisTrack.FxWinLocation.int2; thisTrack.vstiWin.Show(); foreach (ActiveVstPlugin avplug in thisTrack.TrackInstrumentVsts) { if (avplug.myContext != null) { int progcount = avplug.myContext.PluginInfo.ProgramCount; for (int progno = 0; progno < progcount; progno++) avplug.VstPrograms.Add(new VstProgram() { ProgramName = avplug.myContext.PluginCommandStub.Commands.GetProgramNameIndexed(progno) }); } } thisTrack.vstiWin.SelectedVstsLV.ItemsSource = thisTrack.TrackInstrumentVsts; //foreach (ActiveVstPlugin vstplugin in thisTrack.TrackInstrumentVsts) // if (vstpluginIsEditorOpen) // switch (vstplugin.myEditorFrame == null) // { // case true: // vstplugin.OpenEditor(fxWindow); // break; // case false: // if (!vstplugin.myEditorFrame.Visible) // vstplugin.OpenEditor(fxWindow); // break; // } } private void ArmBut_Click(object sender, RoutedEventArgs e) { Track currentlyArmedTrack = editingProject.GetAllTracksInProject.Where(trk => trk.IsRecordingArmed).FirstOrDefault(); thisTrack.IsRecordingArmed = !thisTrack.IsRecordingArmed; if (currentlyArmedTrack != null) { //currentlyArmedTrack.IsRecordingArmed = false; switch (currentlyArmedTrack.trackType) { case TrackType.Audio: projPlayer.DisarmForAudioRecording(); break; case TrackType.Midi: projPlayer.DisarmForMidiRecording(); break; } currentlyArmedTrack.IsRecordingArmed = false; //PUT HERE?? } if (thisTrack.IsRecordingArmed) { switch (thisTrack.trackType) { case TrackType.Audio: try { projPlayer.ArmForAudioRecording(Settings.Default.RecordInIndex); } catch { MessageBox.Show("Unable to arm for audio recording."); projPlayer.AudioDeviceOK = false; projPlayer.UnarmAudio(); projPlayer.CreateNewAsioOut(); thisTrack.IsRecordingArmed = false; } break; case TrackType.Midi: try { projPlayer.ArmForMidiRecording(thisTrack.currentMidiInDeviceNo); } catch { MessageBox.Show("Unable to arm for midi recording."); thisTrack.IsRecordingArmed = false; } break; } } } private void DuplicateTrackMenuItem_Click(object sender, RoutedEventArgs e) { ShowProcessingMessage("Duplicating track . . ."); Dispatcher.InvokeAsync(() => { string trackJson = GetJsonForTrack(thisTrack); Track dupeTrack = CreateTrackFromJson(trackJson); dupeTrack.TrackName = thisTrack.TrackName + " - copy"; if (thisTrack.parentTrack == null) editingProject.Tracks.Insert(thisTrack.GetTrackIndex + 1, dupeTrack); else thisTrack.parentTrack.SubTracks.Insert(thisTrack.GetTrackIndex + 1, dupeTrack); undoActions.Add(new TrackDuplicateUndo(dupeTrack.UndoTrackID)); //dupeTrack.InitializeTrackAudio(); editingProject.UpdateAllClips(editingProject.Tracks); editingProject.NeedsSaving = true; HideProcessingMessage(); }, System.Windows.Threading.DispatcherPriority.Background); } private void TextBlock_ContextMenuOpening(object sender, ContextMenuEventArgs e) { ClearClipsMI.IsEnabled = thisTrack.IsProjectPlayingEnabled; DeleteTrackMI.IsEnabled = thisTrack.IsProjectPlayingEnabled; DupeTrackMI.IsEnabled = thisTrack.IsProjectPlayingEnabled; AddSubTrackMI.Visibility = thisTrack.trackType == TrackType.Submix ? Visibility.Visible : Visibility.Collapsed; } private void ArmBut_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (thisTrack.trackType == TrackType.Audio | thisTrack.IsRecordingArmed) { e.Handled = true; return; } ContextMenu thisCM = ((Button)sender).ContextMenu; thisCM.Items.Clear(); for (int mi = 0; mi < MidiIn.NumberOfDevices; mi++) { MenuItem newMI = new MenuItem() { Header = MidiIn.DeviceInfo(mi).ProductName }; newMI.IsCheckable = true; newMI.Click += NewMI_Click; thisCM.Items.Add(newMI); if (mi == thisTrack.currentMidiInDeviceNo) newMI.IsChecked = true; } } private void NewMI_Click(object sender, RoutedEventArgs e) { MenuItem thisMI = (MenuItem)sender; ContextMenu thisCM = (ContextMenu)thisMI.Parent; if (thisMI.IsChecked) thisTrack.currentMidiInDeviceNo = thisCM.Items.IndexOf(thisMI); else thisTrack.currentMidiInDeviceNo = -1; thisTrack.UpdateRecInToolTip(); } private void RecordAutomationBut_Click(object sender, RoutedEventArgs e) { Track thisTrack = (Track)this.DataContext; if (!thisTrack.IsAutomationRecording && projPlayer.IsProjectPlaying) return; if (AutomationLanesCB.SelectedIndex == -1) return; AutomationLane thisAutoLane = thisTrack.AutomationLanes[AutomationLanesCB.SelectedIndex]; thisTrack.IsAutomationRecording = !thisTrack.IsAutomationRecording; switch (thisTrack.IsAutomationRecording) { case true: thisAutoLane.InitialInsertIdx = thisAutoLane.autoPoints.IndexOf(thisAutoLane.autoPoints.FirstOrDefault(ap => ap.sourcePointms > projPlayer.CurrentPlayingPosMS)); thisAutoLane.AutoRecordedPointCount = 0; thisAutoLane.AutoRemovedPoints.Clear(); thisAutoLane.AutoPointsVisible = true; thisTrack.AutomationRecordingStartMs = projPlayer.CurrentPlayingPosMS; thisTrack.LastAutoRecMasterTime = projPlayer.CurrentPlayingPosMS; thisTrack.compareAutoPoints = new List(thisAutoLane.autoPoints); thisAutoLane.RecAnchorAutoPoint.sourcePointms = projPlayer.CurrentPlayingPosMS; float newValue = thisTrack.GetCurrentSourceValue; thisAutoLane.RecAnchorAutoPoint.AutoValue = newValue; thisAutoLane.autoPoints.Insert(thisAutoLane.InitialInsertIdx, thisAutoLane.RecAnchorAutoPoint); thisAutoLane.autoPoints.Insert(thisAutoLane.InitialInsertIdx, new AutoPoint() { sourcePointms = projPlayer.CurrentPlayingPosMS, AutoValue = newValue }); thisAutoLane.AutoRecordedPointCount += 1; break; case false: int lastIdx = thisAutoLane.autoPoints.IndexOf(thisAutoLane.RecAnchorAutoPoint); if (lastIdx > -1 && lastIdx < thisAutoLane.autoPoints.Count) { thisAutoLane.autoPoints.Insert(lastIdx, new AutoPoint() { sourcePointms = thisAutoLane.RecAnchorAutoPoint.sourcePointms, AutoValue = thisAutoLane.RecAnchorAutoPoint.AutoValue }); thisAutoLane.AutoRecordedPointCount += 1; } thisAutoLane.autoPoints.Remove(thisAutoLane.RecAnchorAutoPoint); undoActions.Add(new AutomationSectionRecordedUndoClass(thisTrack.UndoTrackID, thisTrack.AutomationLanes.IndexOf(thisAutoLane), thisAutoLane.InitialInsertIdx, thisAutoLane.AutoRecordedPointCount, thisAutoLane.AutoRemovedPoints)); thisTrack.compareAutoPoints.Clear(); break; } projPlayer.TogglePlayPauseCurrentProject(); editingProject.AutomationRecordingEnabled = !thisTrack.IsAutomationRecording; projPlayer.PlayControlsDPDisabled = thisTrack.IsAutomationRecording; ((EditorWindow)App.Current.MainWindow).MarkersCB.IsEnabled = !thisTrack.IsAutomationRecording; ((EditorWindow)App.Current.MainWindow).ShowMenuBut.IsEnabled = !thisTrack.IsAutomationRecording; foreach (Track t in editingProject.GetAllTracksInProject) t.UpdateAutomationRecordingEnabled(); } private void ClearAllClipsInTrackMenuItem_Click(object sender, RoutedEventArgs e) { Track thisTrack = (Track)this.DataContext; if (MessageBox.Show("Delete all clips in track?:\n" + thisTrack.TrackName, "Clear track of clips", MessageBoxButton.YesNo) == MessageBoxResult.No) return; List clipJsons = new List(); for (int clipno = thisTrack.Clips.Count - 1; clipno > -1; clipno -= 1) // clearing collection does not trigger collection changed { clipJsons.Add(GetJsonForClip(thisTrack.Clips[clipno])); thisTrack.RemoveAndDisposeClip(thisTrack.Clips[clipno]); } undoActions.Add(new TrackClearAllClipsUndo(thisTrack.UndoTrackID, clipJsons)); } private void SubTrackControl_Loaded(object sender, RoutedEventArgs e) { //SubTrackControlsIC.Height = Math.Min(TrackControlsSV.Height - 20, TrackControlsIC.Items.Count * 80); } private void AddAudioSubtrackMenuItem_Click(object sender, RoutedEventArgs e) { Track newSubmixtrack = new Track(TrackType.Audio) { TrackName = "New audio subtrack" }; thisTrack.SubTracks.Add(newSubmixtrack); undoActions.Add(new TrackAddUndo(newSubmixtrack.UndoTrackID)); } private void AddMidiSubTrackBut_Click(object sender, RoutedEventArgs e) { Track newSubmixtrack = new Track(TrackType.Midi) { TrackName = "New midi submix" }; thisTrack.SubTracks.Add(newSubmixtrack); undoActions.Add(new TrackAddUndo(newSubmixtrack.UndoTrackID)); } private void AddSubMixSubTrackBut_Click(object sender, RoutedEventArgs e) { Track newSubmixtrack = new Track(TrackType.Submix) { TrackName = "New submix subtrack" }; thisTrack.SubTracks.Add(newSubmixtrack); undoActions.Add(new TrackAddUndo(newSubmixtrack.UndoTrackID)); } private void TrackControl_Drop(object sender, DragEventArgs e) { editingProject.TrackDropCompleted(); } private void TrackControl_DragOver(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effects = DragDropEffects.None; e.Handled = true; return; } double thisTCTop = thisTrack.GetActualTrackTop; double relativeTCTop = e.GetPosition(this).Y + editingProject.trackFloatCanvas.mousedownY; double movingTCTop = thisTCTop + (editingProject.MasterTrack.IsTrackCollapsed ? 0 : 80 * editingProject.MasterTrack.TrackYScale) + relativeTCTop; if (thisTrack != editingProject.dragOverTrack) { editingProject.dragOverTrack = thisTrack; if (thisTrack.GetActualTrackHeight > editingProject.movingTrack.GetActualTrackHeight) { bool targetTopAbove = thisTCTop < movingTCTop; bool TargetBotBelow = thisTCTop + thisTrack.GetActualTrackHeight > movingTCTop + editingProject.movingTrack.GetActualTrackHeight; if (!(targetTopAbove & TargetBotBelow)) MoveTrack(editingProject.movingTrack, thisTrack); } else MoveTrack(editingProject.movingTrack, thisTrack); } editingProject.trackFloatCanvas.Top = movingTCTop - editingProject.TracksContentSVVerticalOffset; editingProject.trackFloatCanvas.Left = 3; e.Handled = true; e.Effects = DragDropEffects.Move; } private void MoveTrack(Track movingTrack, Track dragOverTrack) { if (movingTrack == dragOverTrack) return; if (dragOverTrack.IsSubmixTrack && dragOverTrack.SubTracks.Count == 0) { if (movingTrack.parentTrack == null) editingProject.Tracks.Remove(movingTrack); else movingTrack.parentTrack.SubTracks.Remove(movingTrack); dragOverTrack.SubTracks.Add(movingTrack); return; } if (movingTrack.parentTrack == null) { int index1 = editingProject.Tracks.IndexOf(movingTrack); if (dragOverTrack.parentTrack == null) editingProject.Tracks.Move(index1, editingProject.Tracks.IndexOf(dragOverTrack)); else { //base level track moved into submix Track t2parentTrack = dragOverTrack.parentTrack; int index2 = t2parentTrack.SubTracks.IndexOf(dragOverTrack); editingProject.Tracks.RemoveAt(index1); t2parentTrack.SubTracks.Insert(index2, movingTrack); } } else { Track t1parentTrack = movingTrack.parentTrack; int index1 = t1parentTrack.SubTracks.IndexOf(movingTrack); if (dragOverTrack.parentTrack == null) { //submix track moved to base level int index2 = editingProject.Tracks.IndexOf(dragOverTrack); t1parentTrack.SubTracks.RemoveAt(index1); editingProject.Tracks.Insert(index2, movingTrack); } else { //submix track to other submix track Track t2parentTrack = dragOverTrack.parentTrack; int index2 = t2parentTrack.SubTracks.IndexOf(dragOverTrack); if (t1parentTrack == t2parentTrack) t1parentTrack.SubTracks.Move(index1, index2); else { t1parentTrack.SubTracks.RemoveAt(index1); t2parentTrack.SubTracks.Insert(index2, movingTrack); } } } } bool MouseDownOnTrackBottom = false; bool MouseOverTrackBottom = false; bool MouseDownOnTrackControlTB = false; double MouseDownY; bool clipsContainerWasResized = false; private void TrackControl_MouseMove(object sender, MouseEventArgs e) { if (this.AutomationLanesCB.IsDropDownOpen) return; if (MouseDownOnTrackBottom) { e.Handled = true; double newPos = e.GetPosition(this).Y - (thisTrack.AutomationLanesVisible ? 60 : 0); thisTrack.TrackHeight = Math.Min(300, Math.Max(80, newPos)); clipsContainerWasResized = true; return; } if (MouseDownOnTrackControlTB) { //e.Handled = true; if (editingProject.Tracks.Count == 1 && thisTrack.parentTrack == null) return; double newYPoint = e.GetPosition(this).Y - MouseDownY; if (Math.Abs(newYPoint) > 6 && MouseDownOnTrackControlTB) { MouseDownOnTrackControlTB = false; editingProject.movingTrack = thisTrack; double trackTop = this.TranslatePoint(new Point(0, 0), App.Current.MainWindow).Y + App.Current.MainWindow.Top + SystemParameters.WindowCaptionHeight + 10; editingProject.trackFloatCanvas.mousedownY = MouseDownY; editingProject.trackFloatCanvas.imgSource = GetScreenAsBitmapSource((int)(App.Current.MainWindow.Left + 15), (int)(trackTop), (int)App.Current.MainWindow.ActualWidth, (int)(this.ActualHeight * thisTrack.TrackYScale)); editingProject.trackFloatCanvas.Height = editingProject.trackFloatCanvas.imgSource.Height / dpiXFac; //???????????????? reverse? editingProject.trackFloatCanvas.Width = editingProject.trackFloatCanvas.imgSource.Width / dpiYFac; editingProject.trackFloatCanvas.IsVisible = true; editingProject.movingTrack.ContentHidden = true; editingProject.movingTrack.preMoveIndex = editingProject.movingTrack.parentTrack == null ? editingProject.Tracks.IndexOf(editingProject.movingTrack) : editingProject.movingTrack.parentTrack.SubTracks.IndexOf(editingProject.movingTrack); editingProject.movingTrack.premovingParentTrack = editingProject.movingTrack.parentTrack; var ret = DragDrop.DoDragDrop(this, "movingtrack", DragDropEffects.All); editingProject.movingTrack.ContentHidden = false; editingProject.trackFloatCanvas.IsVisible = false; } return; } if (e.GetPosition(this).Y > this.ActualHeight - 6) { MouseOverTrackBottom = true; Cursor = Cursors.SizeNS; } else { MouseOverTrackBottom = false; Cursor = Cursors.Arrow; } } double previousTrackHeight = 1; private void TrackControl_MouseDown(object sender, MouseButtonEventArgs e) { if (e.OriginalSource.GetType() == typeof(TextBlock)) { if (editingProject.GetAllTracksInProject.Where(t => !t.IsTrackCollapsed).Count() > 1) { if (!projPlayer.IsProjectPlaying) MouseDownOnTrackControlTB = true; MouseDownY = e.GetPosition(this).Y; } } MouseDownOnTrackBottom = MouseOverTrackBottom; if (MouseDownOnTrackBottom) { Track thisTrack = (Track)this.DataContext; previousTrackHeight = thisTrack.TrackHeight; this.CaptureMouse(); } } private void TrackControl_MouseUp(object sender, MouseButtonEventArgs e) { this.ReleaseMouseCapture(); MouseDownOnTrackControlTB = false; MouseDownOnTrackBottom = false; MouseOverTrackBottom = false; Cursor = Cursors.Arrow; } private void TrackControl_MouseLeave(object sender, MouseEventArgs e) { if (clipsContainerWasResized) { editingProject.NeedsSaving = true; clipsContainerWasResized = false; Track thisTrack = (Track)this.DataContext; undoActions.Add(new TrackHeightResizeUndo(thisTrack.UndoTrackID, previousTrackHeight)); } this.ReleaseMouseCapture(); MouseDownOnTrackControlTB = false; MouseDownOnTrackBottom = false; MouseOverTrackBottom = false; Cursor = Cursors.Arrow; } private void ToggleCollapseSubmixTrackBut_Click(object sender, RoutedEventArgs e) { thisTrack.SubTracksVisible = !thisTrack.SubTracksVisible; undoActions.Add(new SubmixToggleUndo(thisTrack.UndoTrackID)); editingProject.NeedsSaving = true; } private void ColorPicker16_MouseDown(object sender, MouseButtonEventArgs e) { ColorPicker16 thisColorPicker = (ColorPicker16)sender; string previousColorString = thisTrack.TrackBackgroundColor.ToString(); thisTrack.TrackBackgroundColor = thisColorPicker.SelectedBrush.Color; undoActions.Add(new TrackColorChangeUndo(thisTrack.UndoTrackID, previousColorString)); editingProject.NeedsSaving = true; } private void ArmBut_MouseEnter(object sender, MouseEventArgs e) { thisTrack.ToolTipText = thisTrack.RecordInDeviceName; } private void ArmBut_MouseLeave(object sender, MouseEventArgs e) { thisTrack.ToolTipText = ""; } private void TrackTypeBut_ContextMenuOpening(object sender, ContextMenuEventArgs e) { Button thisBut = (Button)sender; ContextMenu thisCM = thisBut.ContextMenu; thisCM.Items.Clear(); if (thisTrack.trackType == TrackType.Midi) { foreach (ActiveVstPlugin avp in thisTrack.TrackInstrumentVsts.Where(tiv => tiv.IsActive)) { if (avp.HasEditor) { MenuItem newMI = new MenuItem() { Header = avp.PluginName }; newMI.Click += TrackTypeButCM_Click; thisCM.Items.Add(newMI); } } thisCM.Visibility = thisCM.Items.Count > 0 ? Visibility.Visible : Visibility.Collapsed; } else thisCM.Visibility = Visibility.Collapsed; } private void TrackTypeButCM_Click(object sender, RoutedEventArgs e) { MenuItem thisMI = (MenuItem)sender; ActiveVstPlugin avp = thisTrack.TrackInstrumentVsts.Where(tiv => tiv.PluginName == thisMI.Header).FirstOrDefault(); if (avp != null) { if (avp.IsEditorOpen) avp.edHostWin.Activate(); else avp.OpenEditor((EditorWindow)App.Current.MainWindow); editingProject.NeedsSaving = true; } } } }