public override bool CanPerform() { var prev = Row.Cells.LookupIndex(Cells.First().Index).Prev(); // can't move if directly above a reference. if (prev != null && !string.IsNullOrEmpty(prev.Cell.Reference) && !prev.Cell.IsSelected) { return(false); } double increment = BeatCell.Parse(Increment) * Times; if (ShiftingRight) { if (Cells.Last().Index == Row.Cells.Count - 1) { return(true); } if (Row.Cells.Count == 1) { return(true); // can always move single cell right } var next = Row.Cells.LookupIndex(Cells.Last().Index).Next(); return(next.Cell.Position > Cells.Last().Position + increment); } if (Cells.First().Index == 0) { return(Row.Offset >= increment); } return(prev.Cell.Position < Cells[0].Position - increment); }
protected override void Transformation() { Group.FactorValue = Factor; Group.Factor = BeatCell.Parse(Factor); ChangesViewWidth = true; }
public virtual void Undo() { // if no change, don't do anything if (AfterBeatCode == BeforeBeatCode) { return; } CellTree selectedCells = EditorViewController.Instance.DView.SelectedCells; // get current selection range if it's in this row int selectionStart = -1; int selectionEnd = -1; // get selection indexes if there is a selection in the action's row if (selectedCells.Root != null && selectedCells.Root.Cell.Row == Row) { // find index of first selected cell selectionStart = selectedCells.Min.Cell.Index; selectionEnd = selectedCells.Max.Cell.Index; } bool selectFromBack = selectionEnd > RightIndexBoundOfTransform; if (selectFromBack) { // get index from back of list selectionStart = Row.Cells.Count - selectionStart; selectionEnd = Row.Cells.Count - selectionEnd; } Row.FillFromBeatCode(BeforeBeatCode); if (BeforeOffset != AfterOffset) { Row.OffsetValue = BeforeOffset; Row.Offset = BeatCell.Parse(BeforeOffset); } if (ChangesViewWidth) { double maxDur = DrawingView.Instance.Rows.Max(x => x.Duration); DrawingView.Instance.ResizeFrame(maxDur, false); } else { EditorViewController.Instance.DView.QueueRowToDraw(Row); RedrawReferencers(); } EditorViewController.Instance.DView.ChangesApplied = false; // would be nice to only draw individual rows, but seems to be a problem //DrawingView.Instance.NeedsDisplay = true; if (selectionStart > -1) { if (selectFromBack) { // convert back to forward indexed selectionStart = Row.Cells.Count - selectionStart; selectionEnd = Row.Cells.Count - selectionEnd; } if (selectionStart < 0) { selectionStart = 0; } if (selectionEnd >= Row.Cells.Count) { selectionEnd = Row.Cells.Count - 1; } // make new selection CellTreeNode startNode = Row.Cells.LookupIndex(selectionStart); CellTreeNode endNode = Row.Cells.LookupIndex(selectionEnd); EditorViewController.Instance.DView.SelectCell(startNode.Cell); if (startNode != endNode) { EditorViewController.Instance.DView.SelectCell(endNode.Cell, true); } } }
public virtual void Redo() { CellTree selectedCells = EditorViewController.Instance.DView.SelectedCells; // get current selection range if it's in this row int selectionStart = -1; int selectionEnd = -1; int rowLengthBefore = Row.Cells.Count; // get selection indexes if there is a selection in the action's row if (selectedCells.Root != null && selectedCells.Root.Cell.Row == Row) { // find index of first selected cell selectionStart = selectedCells.Min.Cell.Index; selectionEnd = selectedCells.Max.Cell.Index; } if (string.IsNullOrEmpty(AfterBeatCode)) { // perform the transform and get the new beat code Transformation(); AfterBeatCode = Row.Stringify(); AfterOffset = Row.OffsetValue; } bool selectFromBack = selectionEnd > RightIndexBoundOfTransform; if (selectFromBack) { // get index from back of list selectionStart = rowLengthBefore - selectionStart; selectionEnd = rowLengthBefore - selectionEnd; } Row.FillFromBeatCode(AfterBeatCode); if (BeforeOffset != AfterOffset) { Row.OffsetValue = AfterOffset; Row.Offset = BeatCell.Parse(AfterOffset); } if (ChangesViewWidth) { double maxDur = DrawingView.Instance.Rows.Max(x => x.Duration); // change the view's width //var curFrame = DrawingView.Instance.Frame; //curFrame.Width = (System.nfloat)(maxDur * DrawingView.ScalingFactor + 550); //DrawingView.Instance.Frame = curFrame; // need to draw the end portion of other rows if (maxDur == Row.Duration) { DrawingView.Instance.ResizeFrame(maxDur); } else { ChangesViewWidth = false; } } DrawingView.Instance.QueueRowToDraw(Row); DrawingView.Instance.ChangesApplied = false; RedrawReferencers(); if (selectionStart > -1) { if (selectFromBack) { // convert back to forward indexed selectionStart = Row.Cells.Count - selectionStart; selectionEnd = Row.Cells.Count - selectionEnd; } if (selectionStart < 0) { selectionStart = 0; } if (selectionEnd >= Row.Cells.Count) { selectionEnd = Row.Cells.Count - 1; } // make new selection CellTreeNode startNode = Row.Cells.LookupIndex(selectionStart); CellTreeNode endNode = Row.Cells.LookupIndex(selectionEnd); if (startNode != null && endNode != null) { EditorViewController.Instance.DView.SelectCell(startNode.Cell); if (startNode != endNode) { EditorViewController.Instance.DView.SelectCell(endNode.Cell, true); } } } }
public RemoveCells(CellTree cells) : base(cells.Root.Cell.Row, cells.Count > 1 ? "Remove Cells" : "Remove Cell") { Cells = cells; //Row = cells.Root.Cell.Row; //PreviousCellValue = previousCellValue; //Index = cells[0].Row.Cells.IndexOf(cells[0]); StartNode = Row.Cells.LookupIndex(cells.Min.Cell.Index); EndNode = Row.Cells.LookupIndex(cells.Max.Cell.Index); StringBuilder duration = new StringBuilder(); // find all groups that are encompassed by the selection HashSet <AbstractGroup> touchedGroups = new HashSet <AbstractGroup>(); Repeat groupBeingAppendedTo = null; // a group who's LTM is actively being augmented Queue <Repeat> rgToAppendTo = new Queue <Repeat>(); // RGs that may need to have their LTM added to //LinkedList<AbstractGroup> openedGroups = new LinkedList<AbstractGroup>(); //LinkedList<AbstractGroup> closedGroups = new LinkedList<AbstractGroup>(); foreach (Cell c in Cells) { //if (!string.IsNullOrEmpty(c.Reference)) continue; foreach ((bool begun, AbstractGroup group) in c.GroupActions) { if (begun) { OpenedGroups.AddFirst(group); } else { ClosedGroups.AddFirst(group); } } // add to the LTM of groups with a previous cell in the selection but not this cell if (rgToAppendTo.Any() && !c.RepeatGroups.Contains(rgToAppendTo.Peek())) { groupBeingAppendedTo = rgToAppendTo.Dequeue(); } if (groupBeingAppendedTo != null) { groupBeingAppendedTo.LastTermModifier = BeatCell.Add(groupBeingAppendedTo.LastTermModifier, c.Value); } int times = 1; // times this cell gets repeated // track the times that each RG's LTM gets repeated Dictionary <Repeat, int> lcmTimes = new Dictionary <Repeat, int>(); foreach (Repeat rg in c.RepeatGroups.Reverse()) { // remove cell from group rg.ExclusiveCells.Remove(c); rg.Cells.Remove(c); // remove break cells if (rg.BreakCell == c) { rg.BreakCell = null; } if (touchedGroups.Contains(rg)) { continue; } rgToAppendTo.Enqueue(rg); touchedGroups.Add(rg); if ( (StartNode.Cell == rg.ExclusiveCells.First?.Value || rg.Position > StartNode.Cell.Position) && (EndNode.Cell == rg.ExclusiveCells.Last?.Value || rg.Position + rg.Length < EndNode.Cell.Position)) { RepGroups.Add(rg); bool cellAboveBreak = rg.BreakCell != null && c.Position > rg.BreakCell.Position; times *= rg.Times - (cellAboveBreak ? 1 : 0); // multiply all nested rgs' LTMs by this groups repeat times. foreach (KeyValuePair <Repeat, int> kv in lcmTimes) { bool aboveBreak = rg.BreakCell != null && kv.Key.Position > rg.BreakCell.Position; lcmTimes[kv.Key] *= rg.Times - (aboveBreak ? 1 : 0); } lcmTimes.Add(rg, 1); } } foreach (Multiply mg in c.MultGroups) { // remove cell from group mg.ExclusiveCells.Remove(c); if (touchedGroups.Contains(mg)) { continue; } touchedGroups.Add(mg); if ( (StartNode.Cell == mg.ExclusiveCells.First.Value || mg.Position > StartNode.Cell.Position) && (EndNode.Cell == mg.ExclusiveCells.Last.Value || mg.Position + mg.Length < EndNode.Cell.Position + EndNode.Cell.Duration)) { MultGroups.Add(mg); } } // get the double version of duration Duration += c.Duration * times; // get the string version of duration // add cell's repeat durations if this cell is in the same scope as the first cell. if ((!c.RepeatGroups.Any() && !StartNode.Cell.RepeatGroups.Any()) || c.RepeatGroups.Last?.Value == StartNode.Cell.RepeatGroups.Last?.Value) { duration.Append("+0").Append(BeatCell.MultiplyTerms(c.Value, times)); } // add any LTM's from repeat groups foreach (KeyValuePair <Repeat, int> kv in lcmTimes) { duration.Append("+0").Append(BeatCell.MultiplyTerms(kv.Key.LastTermModifier, kv.Value)); Duration += BeatCell.Parse(kv.Key.LastTermModifier) * kv.Value; } } // Transfer group actions from deleted cells to the 2 cells outside the deleted group //CellTreeNode after = EndNode.Next(); //CellTreeNode before = StartNode.Prev(); // //if (after != null) //{ // foreach (AbstractGroup group in openedGroups) // { // if (group.ExclusiveCells.Count > 0) // { // after.Cell.GroupActions.AddFirst((true, group)); // } // } //} // //if (before != null) //{ // foreach (AbstractGroup group in closedGroups) // { // if (group.ExclusiveCells.Count > 0) // { // before.Cell.GroupActions.AddFirst((false, group)); // } // } //} BeatCodeDuration = BeatCell.SimplifyValue(duration.ToString()); }