/// <summary> /// Adds the cell below row. /// </summary> protected void AddCellBelowRow() { Cell cell = new Cell(Row); // get the value string StringBuilder val = new StringBuilder(); int ltmFactor = 1; CellTreeNode c = Row.Cells.Min; while (c != FirstSelected) { if (!string.IsNullOrEmpty(c.Cell.Reference)) { c = c.Next(); continue; } AddCellValueToAccumulator(c.Cell, Row.Cells.Min.Cell, FirstSelected.Cell, val, ref ltmFactor); c = c.Next(); } val.Append('0').Append(BeatCell.MultiplyTerms(BeatCell.Invert(DrawingView.Instance.GridSpacingString), NumIntervals)); cell.Value = BeatCell.Invert(BeatCell.SimplifyValue(val.ToString())); // does having negative positions like this cause problems? cell.Position = FirstSelected.Cell.Position - DrawingView.Instance.GridSpacing * NumIntervals; Row.Cells.Insert(cell); RightIndexBoundOfTransform = -1; Row.OffsetValue = BeatCell.Subtract(Row.OffsetValue, cell.Value); // don't mult group factor this }
/// <summary> /// Adds the cell to the other cell's groups when applicable /// </summary> /// <param name="cell">Cell.</param> /// <param name="below">Below.</param> private static void AddToGroups(Cell cell, Cell below) { foreach (Repeat rg in below.RepeatGroups.Where(x => x.ActualPosition + x.Length > cell.Position)) { //rg.Cells.Last.Value.GroupActions.Remove(); cell.RepeatGroups.AddLast(rg); // transfer actions if below was last cell of group if (rg.ExclusiveCells.Last.Value == below) { below.GroupActions.Remove((false, rg)); cell.GroupActions.AddLast((false, rg)); } } foreach (Multiply mg in below.MultGroups.Where(x => x.ActualPosition + x.Length > cell.Position)) { cell.MultGroups.AddLast(mg); if (UserSettings.GetSettings().DrawMultToScale) { cell.MultFactor = BeatCell.MultiplyTerms(cell.MultFactor, mg.FactorValue); } if (mg.ExclusiveCells.Last.Value == below) { below.GroupActions.Remove((false, mg)); cell.GroupActions.AddLast((false, mg)); } } }
public string GetValueDividedByMultFactor(string value, bool ignoreSetting = false) { if (string.IsNullOrEmpty(value) || (!ignoreSetting && !UserSettings.GetSettings().DrawMultToScale)) { return(value); } return(BeatCell.DivideTerms(value, MultFactor)); }
public override void Redo() { base.Redo(); if (ChangeOffset) { Row.Offset += Duration; Row.OffsetValue = BeatCell.Add(Row.OffsetValue, BeatCodeDuration); } }
public override void Undo() { base.Undo(); if (ChangeOffset) { Row.Offset -= Duration; Row.OffsetValue = BeatCell.Subtract(Row.OffsetValue, BeatCodeDuration); } }
/// <summary> /// Gets the ltm with mult factor. /// </summary> /// <returns>The ltm with mult factor.</returns> public string GetLtmWithMultFactor(bool ignoreSettings = false) { if (string.IsNullOrEmpty(LastTermModifier) || (!ignoreSettings && !UserSettings.GetSettings().DrawMultToScale)) { return(LastTermModifier); } if (string.IsNullOrEmpty(MultedLtm)) { MultedLtm = BeatCell.MultiplyTerms(LastTermModifier, MultFactor); } return(MultedLtm); }
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); }
/// <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); } } }
/// <summary> /// Adds the cell to row above selection. /// </summary> protected void AddCellToRowAboveSelection() { Cell cell = new Cell(Row); CellTreeNode node = new CellTreeNode(cell); cell.Position = LastSelected.Cell.Position + NumIntervals * DrawingView.Instance.GridSpacing; if (Row.Cells.Insert(node)) { CellTreeNode belowNode = node.Prev(); Cell below = belowNode.Cell; RightIndexBoundOfTransform = below.Index + 1; // add to applicable groups AddToGroups(cell, below); // is new cell placed in the LTM zone of a rep group? Repeat repWithLtmToMod = null; foreach (Repeat rg in below.RepeatGroups.Where( x => x.ExclusiveCells.Last.Value == below && Position > below.Position + below.ActualDuration)) { repWithLtmToMod = rg; } // determine new value for the below cell StringBuilder val = new StringBuilder(); var sequence = LastSelected.Cell.RepeatGroups .Where(x => !cell.RepeatGroups.Contains(x) && x.Cells.First.Value != LastSelected.Cell) .Reverse() .Select(x => x.Times); int ltmFactor = sequence.Any() ? sequence.Aggregate((x, y) => x * y) : 1; CellTreeNode c = LastSelected; // we subtract all values up to the "whitespace" below the new cell while (c != node) { if (!string.IsNullOrEmpty(c.Cell.Reference)) { c = c.Next(); continue; } AddCellValueToAccumulator(c.Cell, LastSelected.Cell, node.Cell, val, ref ltmFactor); c = c.Next(); } val.Append('0').Append(BeatCell.MultiplyTerms(BeatCell.Invert(DrawingView.Instance.GridSpacingString), NumIntervals)); // get new cells value by subtracting old value of below cell by new value. string newVal = BeatCell.SimplifyValue(val.ToString()); // placing a new cell on the beginning of a LTM is not illegal if (repWithLtmToMod != null && newVal == string.Empty) { newVal = "0"; } // assign the new cell's value cell.Value = BeatCell.SimplifyValue(cell.GetValueDividedByMultFactors(newVal)); if (repWithLtmToMod == null) { // change below cell's value below.Value = below.GetValueDividedByMultFactors( BeatCell.Subtract(below.Value, newVal)); below.Value = BeatCell.SimplifyValue(below.Value); if (below.IsBreak) { below.IsBreak = false; cell.IsBreak = true; } } else { // changing a LTM value repWithLtmToMod.LastTermModifier = BeatCell.SimplifyValue( repWithLtmToMod.GetValueDividedByMultFactor( BeatCell.Subtract(repWithLtmToMod.LastTermModifier, newVal))); } } }
/** * 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() { 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); } } }
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; }
/// <summary> /// Add a cell's value to the accumulator the correct number of times /// </summary> /// <param name="target"></param> /// <param name="start"></param> /// <param name="end"></param> /// <param name="accumulator"></param> /// <param name="ltmFactor"></param> /// <param name="recursing"></param> protected void AddCellValueToAccumulator(Cell target, Cell start, Cell end, StringBuilder accumulator, ref int ltmFactor, bool recursing = false) { // subtract each value from the total if (!target.RepeatGroups.Any()) { accumulator.Append(target.GetValueWithMultFactors()).Append('+'); return; } int timesDiff = 1; int ltmTimesDiff = 1; bool isBehind = target.RepeatGroups.First.Value.Position + target.RepeatGroups.First.Value.FullDuration < start.Position; bool contains = !isBehind; int times = 1; foreach (Repeat rg in target.RepeatGroups.TakeWhile(x => !end.RepeatGroups.Contains(x))) // iterate from innermost group { if (recursing) { if (contains && rg.ExclusiveCells.Contains(start)) { // this is the times to subtract because they occur before the starting point. timesDiff = times; } else if (isBehind && rg.Cells.Contains(start)) { // subtract a full cycle if this rep group exists all behind the target ltmTimesDiff = timesDiff = times; ltmTimesDiff /= target.RepeatGroups.First().Times; isBehind = false; } } // break cell(s) may decrease the factor if (rg.BreakCell != null) { times *= rg.Times - (target == rg.BreakCell || target.Position < rg.BreakCell.Position ? 0 : 1); } else { times *= rg.Times; } if (contains && recursing && rg.ExclusiveCells.Contains(start)) { ltmTimesDiff = times; ltmTimesDiff /= target.RepeatGroups.First().Times; } } // handle LTMs foreach ((bool opens, AbstractGroup rg) in target.GroupActions.Where(x => x.Item2 is Repeat && !end.RepeatGroups.Contains(x.Item2))) { if (!opens) { ltmFactor /= ((Repeat)rg).Times; // subtract out the LTM (if group doesn't contain the end point) if (!string.IsNullOrEmpty((rg as Repeat).LastTermModifier)) { accumulator.Append( BeatCell.MultiplyTerms( ((Repeat)rg).GetLtmWithMultFactor(), ltmFactor - (recursing ? ltmTimesDiff : 0))).Append('+'); } } else if (!end.RepeatGroups.Contains(rg)) { ltmFactor *= ((Repeat)rg).Times; } } // account for preceding cells if we are starting mid-way through a rep group if (recursing) { times -= timesDiff; } else if (target == start) { // find outermost rep group that doesn't contain the new cell Repeat rg = target.RepeatGroups.Reverse().SkipWhile(x => end.RepeatGroups.Contains(x)).FirstOrDefault(); if (rg != null) { int ltmFactorR = 1;//rg.Cells.First.Value == target ? 1 : rg.Times; foreach (Cell c in rg.Cells.TakeWhile(x => x.Position < target.Position)) { AddCellValueToAccumulator(c, start, end, accumulator, ref ltmFactorR, true); } } } if (!string.IsNullOrEmpty(target.Value)) { accumulator.Append(BeatCell.MultiplyTerms(target.GetValueWithMultFactors(), times)).Append('+'); } }
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); } } } }