Example #1
0
        /// <summary>
        /// Look up the cell at the specified BPM position.
        /// </summary>
        /// <returns>The up.</returns>
        /// <param name="value">Value.</param>
        /// <param name="useThickness">If set to <c>true</c> use thickness.</param>
        public CellTreeNode Lookup(double value, bool useThickness = true, double thickness = DrawingView.CellWidth)
        {
            CellTreeNode node = Root;

            thickness /= DrawingView.ScalingFactor;

            while (node != null)
            {
                if (node.Cell.Position + (useThickness ? thickness : 0) >= value && value >= node.Cell.Position)
                {
                    return(node);
                }

                if (node.Cell.Position < value)
                {
                    node = node.Right;
                }
                else
                {
                    node = node.Left;
                }
            }

            return(null);
        }
Example #2
0
 /// <summary>
 /// Clear this instance.
 /// </summary>
 public void Clear()
 {
     Root  = null;
     Min   = null;
     Max   = null;
     Count = 0;
 }
Example #3
0
        /// <summary>
        /// Rotate such that if node was the root, node's right child will now be root
        /// </summary>
        /// <param name="node">Node.</param>
        protected void RotateLeft(CellTreeNode node)
        {
            var rightLeft = node.Right.Left;

            if (Root != node)
            {
                if (node.Parent.Left == node)
                {
                    node.Parent.Left = node.Right;
                }
                else
                {
                    node.Parent.Right = node.Right;
                }
            }
            else
            {
                Root = node.Right;
            }

            node.Right.Parent = node.Parent;
            node.Right.Left   = node;
            node.Parent       = node.Right;
            node.Right        = rightLeft;

            if (rightLeft != null)
            {
                rightLeft.Parent = node;
            }
        }
Example #4
0
        /// <summary>
        /// Rotate such that if node was root, node's left child will now be root
        /// </summary>
        /// <param name="node">Node.</param>
        protected void RotateRight(CellTreeNode node)
        {
            var leftRight = node.Left.Right;

            if (Root != node)
            {
                if (node.Parent.Left == node)
                {
                    node.Parent.Left = node.Left;
                }
                else
                {
                    node.Parent.Right = node.Left;
                }
            }
            else
            {
                Root = node.Left;
            }

            node.Left.Parent = node.Parent;
            node.Left.Right  = node;
            node.Parent      = node.Left;
            node.Left        = leftRight;

            if (leftRight != null)
            {
                leftRight.Parent = node;
            }
        }
Example #5
0
        /// <summary>
        /// Finds the node at bpm position below or equal to value.
        /// </summary>
        /// <returns>The below or equal to.</returns>
        /// <param name="value">Value.</param>
        public CellTreeNode FindBelowOrEqualTo(double value)
        {
            CellTreeNode node   = Root;
            CellTreeNode result = null;

            if (node == null)
            {
                return(null);
            }

            while (node != null)
            {
                if (node.Cell.Position <= value)
                {
                    result = node;

                    if (node.Cell.Position == value)
                    {
                        break;
                    }
                }

                if (node.Cell.Position > value)
                {
                    node = node.Left;
                }
                else
                {
                    node = node.Right;
                }
            }

            return(result);
        }
Example #6
0
        /// <summary>
        /// Replace the specified node with the given replacement and remove original node from the tree.
        /// </summary>
        /// <returns>The replace.</returns>
        /// <param name="node">Node.</param>
        /// <param name="replacement">Replacement.</param>
        protected void Replace(CellTreeNode node, CellTreeNode replacement)
        {
            if (node.Parent == null)
            {
                Root = replacement;
                if (replacement != null)
                {
                    replacement.Parent = null;
                }
            }
            else
            {
                if (node.Parent.Left == node)
                {
                    node.Parent.Left = replacement;
                }
                else
                {
                    node.Parent.Right = replacement;
                }

                if (replacement != null)
                {
                    replacement.Parent = node.Parent;
                }
            }
        }
Example #7
0
        public bool TryFind(double value, out Cell cell, bool useThickness = true)
        {
            CellTreeNode node = Lookup(value, useThickness);

            cell = node?.Cell;

            return(cell != null);
        }
Example #8
0
        /// <summary>
        /// Find all cells inside the given range.
        /// </summary>
        /// <returns>The range.</returns>
        /// <param name="start">Start.</param>
        /// <param name="end">End.</param>
        public CellTreeNode[] GetRange(double start, double end)
        {
            List <CellTreeNode> cells = new List <CellTreeNode>();

            CellTreeNode cell = FindAboveOrEqualTo(start);

            while (cell != null && cell.Cell.Position <= end)
            {
                cells.Add(cell);

                cell = cell.Next();
            }

            return(cells.ToArray());
        }
Example #9
0
        public IEnumerator GetEnumerator()
        {
            CellTreeNode node = Min;

            if (node == null)
            {
                yield break;
            }

            while (node != null)
            {
                yield return(node.Cell);

                node = node.Next();
            }

            yield break;
        }
Example #10
0
        /// <summary>
        /// Finds a node with the given cell index.
        /// </summary>
        /// <returns>The index.</returns>
        /// <param name="index">Index.</param>
        public CellTreeNode LookupIndex(int index)
        {
            CellTreeNode node = Root;

            while (node != null)
            {
                if (node.Cell.Index == index)
                {
                    return(node);
                }

                if (node.Cell.Index < index)
                {
                    node = node.Right;
                }
                else
                {
                    node = node.Left;
                }
            }

            return(null);
        }
Example #11
0
        /// <summary>
        /// Find the first cell above or equal to the given BPM position.
        /// </summary>
        /// <returns>The above or equal to.</returns>
        /// <param name="value">Value.</param>
        public CellTreeNode FindAboveOrEqualTo(double value, bool useThickness = false)
        {
            CellTreeNode node   = Root;
            CellTreeNode result = null;

            if (node == null)
            {
                return(null);
            }

            double thickness = useThickness ? DrawingView.CellWidth / DrawingView.ScalingFactor : 0;

            while (node != null)
            {
                if (node.Cell.Position + thickness >= value)
                {
                    result = node;

                    if (node.Cell.Position + thickness == value)
                    {
                        break;
                    }
                }

                if (node.Cell.Position + thickness < value)
                {
                    node = node.Right;
                }
                else
                {
                    node = node.Left;
                }
            }

            return(result);
        }
 public void CopyTo(CellTreeNode node)
 {
     node.Cell = Cell;
 }
Example #13
0
        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);
                }
            }
        }
Example #14
0
        public CellTree Remove(double value)
        {
            CellTreeNode node = Lookup(value, false);

            return(Remove(node));
        }
Example #15
0
        public CellTree Remove(CellTreeNode node)
        {
            CellTreeNode nodeToDeleteAfterwards = null;

            if (node == Min)
            {
                Min = node.Next();
            }
            else if (node == Max)
            {
                Max = node.Prev();
            }

            if (node.Left == null && node.Right == null)
            {
                if (Root == node)
                {
                    Root = null;
                    Min  = null;
                    Max  = null;
                    return(this);
                }

                if (node.IsRed)
                {
                    Replace(node, null);
                    return(this);
                }

                // black node with no children, not root

                // we will delete the node afterwards. it's a 'phantom' leaf.
                nodeToDeleteAfterwards = node;
                // do we need to track the actual node, as it may be changed by a rule?
            }
            else if (node.Left != null && node.Right != null)
            {
                // we find the left-most child of right side and copy it's value to the node being deleted
                // The node that we copied from (left-most) can then by deleted because it
                // has at most 1 non-leaf child.

                var succesor = node.Left;
                while (succesor.Right != null)
                {
                    succesor = succesor.Right;
                }

                // copy data from succesor node
                succesor.CopyTo(node);

                //Swap(node, succesor);

                return(Remove(succesor));
            }

            if (node.Left != null || node.Right != null)
            {
                // one child is a non-leaf

                var child = node.Left ?? node.Right;


                if (!node.IsRed && child.IsRed)
                {
                    // black node, red child
                    Replace(node, child);

                    child.IsRed = false;
                    return(this);
                }

                if (node.IsRed && !child.IsRed)
                {
                    // red node, black child
                    Replace(node, child);
                    return(this);
                }


                // black node with black child
                Replace(node, child);
                node = child;
            }

            while (true)
            {
                // node is now a "double black" node

                if (node == Root)
                {
                    break;                     // case 1. terminal case
                }

                var sibling = node.GetSibling();

                if (sibling.IsRed)
                {
                    // case 2
                    // node is black, has black parent, and a red sibling
                    // make sibling take the place of the parent.
                    if (node.Parent.Left == node)
                    {
                        RotateLeft(node.Parent);
                    }
                    else
                    {
                        RotateRight(node.Parent);
                    }

                    node.Parent.IsRed = true;
                    sibling.IsRed     = false;
                    sibling           = node.GetSibling();
                }

                else if (!node.Parent.IsRed && !sibling.IsRed && (sibling.Left == null || !sibling.Left.IsRed) && (sibling.Right == null || !sibling.Right.IsRed))
                {
                    // case 3
                    // node is black, black parent, black sibling with black children

                    sibling.IsRed = true;

                    node = node.Parent;
                    // go to start with parent as new node. (we pushed the double black status up to the parent)
                    continue;
                }

                else if (node.Parent.IsRed && (sibling.Left == null || !sibling.Left.IsRed) && (sibling.Right == null || !sibling.Right.IsRed))
                {
                    // case 4, terminal case
                    node.Parent.IsRed = false;
                    sibling.IsRed     = true;
                    break;
                }

                else if (!sibling.IsRed && node.HasSiblingWithInnerRedChild())
                {
                    // case 5
                    // black node, black parent, black sibling with inner red child
                    if (node.Parent.Left == node)
                    {
                        RotateRight(sibling);
                        sibling.Left.IsRed = false;
                    }
                    else
                    {
                        RotateLeft(sibling);
                        sibling.Right.IsRed = false;
                    }

                    sibling.IsRed = true;
                    sibling       = node.GetSibling();
                }

                if (!sibling.IsRed && node.HasSiblingWithOuterRedChild())
                {
                    // case 6, terminal case
                    // black node, don't care parent's color, black sibling with outer red child and inner child with either color.
                    if (node.Parent.Left == node)
                    {
                        RotateLeft(node.Parent);
                        sibling.Right.IsRed = false;
                    }
                    else
                    {
                        RotateRight(node.Parent);
                        sibling.Left.IsRed = false;
                    }

                    sibling.IsRed     = node.Parent.IsRed;
                    node.Parent.IsRed = false;

                    // node is no longer a bouble black.
                    break;
                }
            }

            if (nodeToDeleteAfterwards != null)
            {
                Replace(nodeToDeleteAfterwards, null);
            }

            Count--;

            return(this);
        }
Example #16
0
        public bool Insert(CellTreeNode node)
        {
            node.IsRed = true;

            CellTreeNode parent = Root;

            if (Root == null)
            {
                Root = node;
                Min  = node;
                Max  = node;
            }
            else
            {
                bool isMin = true;
                bool isMax = true;
                while (true)
                {
                    if (parent.Cell.Position > node.Cell.Position)
                    {
                        isMax = false;

                        if (parent.Left == null)
                        {
                            parent.Left = node;
                            break;
                        }

                        parent = parent.Left;
                    }
                    else
                    {
                        isMin = false;

                        if (parent.Cell.Position == node.Cell.Position)
                        {
                            // no overlapping
                            return(false);
                        }

                        if (parent.Right == null)
                        {
                            parent.Right = node;
                            break;
                        }

                        parent = parent.Right;
                    }
                }

                if (isMin)
                {
                    Min = node;
                }
                else if (isMax)
                {
                    Max = node;
                }

                node.Parent = parent;
            }

            // operate on tree to assert red-black properties
            while (node != null)
            {
                //var parent = node.Parent;

                // step 1
                if (parent == null)
                {
                    node.IsRed = false;
                    break;
                }

                // step 2
                if (!parent.IsRed)
                {
                    break;
                }

                var uncle = node.GetUncle();
                var gp    = node.GetGrandParent();

                // step 3
                // check if both parent and uncle are red
                if (uncle != null && uncle.IsRed)
                {
                    node.Parent.IsRed = uncle.IsRed = false;
                    gp.IsRed          = true;
                    node   = gp;
                    parent = gp.Parent;
                    continue;                     // recurse with GP because it's now red
                }

                // step 4
                if (gp.Left != null && gp.Left.Right == node)
                {
                    // rotate
                    RotateLeft(parent);

                    // parent is new node, will be target of step 5
                    node   = parent;
                    parent = node.Parent;
                }
                else if (gp.Right != null && gp.Right.Left != null && gp.Right.Left == node)
                {
                    // mirror of above
                    RotateRight(parent);

                    node   = parent;
                    parent = node.Parent;
                }

                // step 5
                // parent becomes GP
                if (gp.Left != null && gp.Left.Left != null && gp.Left.Left == node)
                {
                    RotateRight(gp);

                    parent.IsRed = false;
                    gp.IsRed     = true;
                }
                else
                {
                    // mirror of above
                    RotateLeft(gp);

                    parent.IsRed = false;
                    gp.IsRed     = true;
                }

                break;
            }

            Count++;

            return(true);
        }
Example #17
0
        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);
                    }
                }
            }
        }