public override void Redo() { base.Redo(); if (ChangeOffset) { Row.Offset += Duration; Row.OffsetValue = BeatCell.Add(Row.OffsetValue, BeatCodeDuration); } }
/// <summary> /// Adds the cell to row below selection. /// </summary> protected void AddCellToRowBelowSelection() { Cell cell = new Cell(Row); CellTreeNode cellNode = new CellTreeNode(cell); cell.Position = FirstSelected.Cell.Position - DrawingView.Instance.GridSpacing * NumIntervals; if (Row.Cells.Insert(cellNode)) { Cell below = cellNode.Prev().Cell; RightIndexBoundOfTransform = below.Index; // add to applicable groups AddToGroups(cell, below); // see if the cell is being added to a rep group's LTM zone Repeat repWithLtmToMod = null; foreach (Repeat rg in below.RepeatGroups.Where( x => x.ExclusiveCells.Last.Value == below && Position > below.Position + below.Duration)) { repWithLtmToMod = rg; } // get new value string for below StringBuilder val = new StringBuilder(); var sequence = cell.RepeatGroups .Where(x => !FirstSelected.Cell.RepeatGroups.Contains(x) && x.Cells.First.Value != cell) .Reverse() .Select(x => x.Times); int ltmFactor = sequence.Any() ? sequence.Aggregate((x, y) => x * y) : 1; CellTreeNode c = cellNode; while (c != FirstSelected) { if (!string.IsNullOrEmpty(c.Cell.Reference)) { c = c.Next(); continue; } AddCellValueToAccumulator(c.Cell, cell, FirstSelected.Cell, val, ref ltmFactor); c = c.Next(); } val.Append('0').Append(BeatCell.MultiplyTerms(BeatCell.Invert(DrawingView.Instance.GridSpacingString), NumIntervals)); cell.Value = BeatCell.SimplifyValue(cell.GetValueDividedByMultFactors(BeatCell.Invert(val.ToString()))); string newValue = BeatCell.SimplifyValue(val.ToString()); if (repWithLtmToMod == null) { below.Value = below.GetValueDividedByMultFactors(BeatCell.Add(below.Value, newValue));//newValue); below.Value = BeatCell.SimplifyValue(below.Value); } else { repWithLtmToMod.LastTermModifier = repWithLtmToMod.GetValueDividedByMultFactor( BeatCell.Subtract(repWithLtmToMod.LastTermModifier, newValue)); repWithLtmToMod.LastTermModifier = BeatCell.SimplifyValue(repWithLtmToMod.LastTermModifier); } } }
/** * In order to have mult group resizing: * 1) Adding to a mult group from flat within that group, * - the interval will need to be multiplied by the group factor * - use the cell values that have said group's factor applied * * 2) adding from inside a mult group to outside that gorup * * 3) adding from before a mult group to after that group * * 4) adding from outside the group, into the group * - like normal, use the actualValue inside of mult group. Multiply result by group factor to get * base value. */ /** * Add above row works like this: * - if placed above all other cells, and above all rep group's LTMs, * increase the previous last cell's or rep group LTM's duration * * get the BPM value of the increment multiplied by how many ticks from last selected cell * * to the new cell * * Then subtract the accumulated value of all cells including rep groups from the total value. * make new cell duration the increment value * * Add above selection, within row works like this: * - Get the value of increment times # of ticks between last selected cell and new cell position * - Subtract the accumulated values of all cells including rep groups to get the new value * of the preceding cell OR a rep group's LTM if we are placing the cell inside of the LTM * - The cells value is then the preceding cell's previous value minus it's new value. * * Add below row works like this: * - Get the value of increment times # of ticks between first selected cell and new cell position * - subtract the accumulated values of all cells and groups between selected cell and new cell * to get the value of the new cell. * - Subtract new cell value from row's offset to get the new offset * * add below section, within row works like this: * - Get the increment * # of ticks value between the first selected cell and new cell postion * - subtract the accumulated values of all cells and groups between selected cell and new cell * to get the value of the new cell. * - subtract new cell value from preceding cell / group LTM's old value to get value * */ /** * Test Cases: * * 1) Above row * 2) Above row where last cell is in a repeat * 3) Above row and within the duration of the last cell * 4) Above selection and within row * 5) ^ Where selection is in a repeat and new cell is not * 6) ^ Where selection and new cell are in the same repeat * 7) ^ Where new cell is in a repeat group * 8) ^ Selection is in a repeat group that is nested * 9) ^ new cell is in a repeat group that is nested * 10) Below selection and within row * 11) ^ Where selection is in a repeat and new cell is not * 12) ^ Where selection and new cell are in the same repeat * 13) ^ Where new cell is in a repeat group * 14) ^ Selection is in a repeat group that is nested * 15) ^ new cell is in a repeat group that is nested * 16) Below the row, in offset area * 17) ^ selection is in a repeat group * 18) ^ there is a repeat group between the selection and the start */ /// <summary> /// Adds the cell above row. /// </summary> protected void AddCellAboveRow() { Cell cell = new Cell(Row); if (cell != null) { cell.Value = BeatCell.SimplifyValue(DrawingView.Instance.GridSpacingString); cell.Position = LastSelected.Cell.Position + DrawingView.Instance.GridSpacing * NumIntervals; // set new duration of previous cell Cell below = Row.Cells.Max.Cell; // if add above a reference, just drop it in and exit. if (below.IsReference) { Row.Cells.Insert(cell); return; } // find the value string StringBuilder val = new StringBuilder(); int ltmFactor = LastSelected.Cell.RepeatGroups.Any() ? LastSelected.Cell.RepeatGroups .Reverse() .Select(x => x.Times) .Aggregate((x, y) => x * y) : 1; CellTreeNode c = LastSelected; while (c != null) { if (!string.IsNullOrEmpty(c.Cell.Reference)) { c = c.Next(); continue; } AddCellValueToAccumulator(c.Cell, LastSelected.Cell, cell, val, ref ltmFactor); c = c.Next(); } val.Append('0').Append(BeatCell.MultiplyTerms(BeatCell.Invert(DrawingView.Instance.GridSpacingString), NumIntervals)); string valToAdd = BeatCell.Invert(BeatCell.SimplifyValue(val.ToString())); // if last cell is in a rep group, we need to increase the LTM for that group if (below.RepeatGroups.Any()) { var rg = below.RepeatGroups.First.Value; // add to the bottom repeat group's LTM rg.LastTermModifier = BeatCell.SimplifyValue(rg.GetValueDividedByMultFactor(valToAdd)); } else { // add to last cell's duration below.Value = BeatCell.Add(below.GetValueDividedByMultFactors(valToAdd), below.Value); } Row.Cells.Insert(cell); ChangesViewWidth = true; } }
protected override void Transformation() { string value = BeatCell.MultiplyTerms(Increment, Math.Abs(Times)); Cell last = Cells[Cells.Length - 1]; Cell first = Cells[0]; if (Row.Cells.Min.Cell == Cells[0]) { // selection is at start of row, offset will be changed if (ShiftingRight) { // add to offset if (string.IsNullOrEmpty(Row.OffsetValue)) { Row.OffsetValue = "0"; } Row.OffsetValue = BeatCell.Add(Row.OffsetValue, first.GetValueDividedByMultFactors(value)); // subtract from last cell's value if not last cell of row if (last != Row.Cells.Max.Cell) { last.Value = BeatCell.Subtract(last.Value, last.GetValueDividedByMultFactors(value)); } } else { // subtract from offset Row.OffsetValue = BeatCell.Subtract(Row.OffsetValue, first.GetValueDividedByMultFactors(value)); // zero becomes an empty string, make it zero. if (string.IsNullOrEmpty(Row.OffsetValue)) { Row.OffsetValue = "0"; } // add to last cell's value if not last cell of row if (last != Row.Cells.Max.Cell) { last.Value = BeatCell.Add(last.Value, last.GetValueDividedByMultFactors(value)); } } } else { Cell below = Row.Cells.LookupIndex(Cells[0].Index - 1).Cell; // if below is last cell of a repeat group, we instead operate on that group's LTM Repeat leftGroup = below.RepeatGroups.Where(x => x.ExclusiveCells.Last.Value == below).FirstOrDefault(); bool useLeftGroup = leftGroup != default(Repeat); // if last cell in selection is last of a repeat group, operate on it's LTM Repeat rightGroup = last.RepeatGroups.Where(x => x.ExclusiveCells.Last.Value == last).FirstOrDefault(); bool useRightGroup = rightGroup != default(Repeat); if (ShiftingRight) { if (Cells.Last() == Row.Cells.Max.Cell) { ChangesViewWidth = true; } if (useLeftGroup) { // add to LTM leftGroup.LastTermModifier = BeatCell.Add(leftGroup.LastTermModifier, leftGroup.GetValueDividedByMultFactor(value)); } else { // add to below cell's value below.Value = BeatCell.Add(below.Value, below.GetValueDividedByMultFactors(value)); } // subtract from last cell's value if not last of row if (last != Row.Cells.Max.Cell) { if (useRightGroup) { // subtract from LTM rightGroup.LastTermModifier = BeatCell.Subtract(rightGroup.LastTermModifier, rightGroup.GetValueDividedByMultFactor(value)); } else { last.Value = BeatCell.Subtract(last.Value, last.GetValueDividedByMultFactors(value)); } } } else { if (useLeftGroup) { // subtract from LTM leftGroup.LastTermModifier = BeatCell.Subtract(leftGroup.LastTermModifier, leftGroup.GetValueDividedByMultFactor(value)); } else { // subtract from below cell's value below.Value = BeatCell.Subtract(below.Value, below.GetValueDividedByMultFactors(value)); } // add to last cell's value if not last in row if (last != Row.Cells.Max.Cell) { if (useRightGroup) { rightGroup.LastTermModifier = BeatCell.Add(rightGroup.LastTermModifier, rightGroup.GetValueDividedByMultFactor(value)); } else { last.Value = BeatCell.Add(last.Value, last.GetValueDividedByMultFactors(value)); } } } } Cells = null; }
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()); }
protected override void Transformation() { Cell firstCell = StartNode.Cell; // remove cells // remove groups foreach (Repeat rg in RepGroups) { Row.RepeatGroups.Remove(rg); } foreach (Multiply mg in MultGroups) { Row.MultGroups.Remove(mg); } // check if first cell of selection is not row's first cell if (firstCell.Index == 0) { // will be increasing the row offset, but only if // selection is not part of a rep group that is not // encompassed by the selection if (!firstCell.RepeatGroups.Any() || !RepGroups.Contains(firstCell.RepeatGroups.First.Value)) { // augment the row's offset ChangeOffset = true; } } else { Cell prevCell = StartNode.Prev().Cell; if (prevCell != null) { // if previous cell is the last cell of a rep group, increase rep groups offset Repeat groupToAddTo = null; foreach (Repeat rg in prevCell.RepeatGroups.Reverse()) { if (!firstCell.RepeatGroups.Contains(rg)) { groupToAddTo = rg; } else { break; } } if (groupToAddTo != null) { groupToAddTo.LastTermModifier = BeatCell.Add(groupToAddTo.LastTermModifier, BeatCodeDuration); } else if (!firstCell.RepeatGroups.Any() || prevCell.RepeatGroups.Contains(firstCell.RepeatGroups.Last.Value)) { // otherwise, increase the prev cell's duration // but only if it is not the cell prior to a repgroup for which first cell of select is first cell of the rep group. prevCell.Value = BeatCell.Add(prevCell.Value, BeatCodeDuration); } // transfer the closing group actions to prev cell foreach (AbstractGroup group in ClosedGroups) { if (RepGroups.Contains(group) || MultGroups.Contains(group)) { continue; } if (prevCell.RepeatGroups.Contains(group) || prevCell.MultGroups.Contains(group)) { prevCell.GroupActions.AddLast((false, group)); } } } } // do the transition of group actions if (EndNode.Cell != Row.Cells.Max.Cell) { Cell nextCell = EndNode.Next().Cell; // need to transfer the repeat group creation point to the next cell (if not a 1 cell group) foreach (AbstractGroup group in OpenedGroups) { if (RepGroups.Contains(group) || MultGroups.Contains(group)) { continue; } if (nextCell.RepeatGroups.Contains(group) || nextCell.MultGroups.Contains(group)) { nextCell.GroupActions.AddFirst((true, group)); } } } // remove cells from tree while (StartNode != null) { var next = StartNode.Next(); Row.Cells.Remove(StartNode); if (StartNode == EndNode) { break; } StartNode = next; } //foreach (CellTreeNode c in Row.Cells.GetRange(StartNode.Cell.Position, EndNode.Cell.Position)) //{ // Row.Cells.Remove(c); //} DrawingView.Instance.DeselectCells(); // no longer need these RepGroups = null; MultGroups = null; Cells = null; StartNode = null; EndNode = null; }