Example #1
0
        /// <summary>
        /// Returns the closest common ancestor object
        /// of this object and <paramref name="other"/>,
        /// or null if <paramref name="other"/> is null,
        /// or if there is no common ancestor.
        /// </summary>
        /// <param name="other">The other object to test.</param>
        /// <returns>The closest common ancestor object
        /// of this object and <paramref name="other"/></returns>
        public GraphElement CommonAncestor(GraphElement other)
        {
            if (other == null)
            {
                return(null);
            }
            if (other == this)
            {
                return(this);
            }
            GraphElement thisw      = this;
            GraphElement otherw     = other;
            int          thisDepth  = this.Depth;
            int          otherDepth = other.Depth;

            while (thisDepth > otherDepth)
            {
                thisw = thisw.parent;
                --thisDepth;
            }
            while (otherDepth > thisDepth)
            {
                otherw = other.parent;
                --otherDepth;
            }
            while (thisw != null && thisw != otherw)
            {
                thisw  = thisw.parent;
                otherw = otherw.parent;
            }
            return(thisw);
        }
Example #2
0
        private void AddChild(GraphElement child)
        {
            // Remove all holes from the sibling index list. Now the max index
            // number is equal to the size of the children list.
            this.EnsureSequentialSiblingIndex();
            this.needSortChildren = true; // maybe false
            child.siblingIndex    = this.childCount;
            //this.children.Add(child);
            if (this.childCount == this.children.Length)
            {
                GraphElement[] childs;
                if (this.childCount == 0)
                {
                    childs = new GraphElement[4];
                }
                else
                {
                    childs = new GraphElement[2 * this.childCount];
                    Array.Copy(this.children, 0, childs, 0, this.childCount);
                }
                this.children = childs;
            }
            this.children[this.childCount++] = child;

            this.OnChildAdded(child);
            System.Drawing.RectangleF invalid = child.ChildrenBoundingBox();
            invalid.Offset(child.X, child.Y);
            this.Invalidate(invalid);
        }
Example #3
0
        /// <summary>
        /// Tests whether or not <paramref name="item1"/>
        /// is on top of or stacked closer to the top
        /// of the display than <paramref name="item2"/>,
        /// in terms of Z-values and parent stacking rules.
        /// </summary>
        /// <param name="item1">The first specified item.</param>
        /// <param name="item2">The second specified item.</param>
        /// <returns>true if <paramref name="item1"/> is closer top
        /// than <paramref name="item2"/>, false otherwise.</returns>
        public static bool ClosestItemFirst(GraphElement item1, GraphElement item2)
        {
            // Siblings? Just check their z-values.
            if (item1.parent == item2.parent)
            {
                return(ClosestLeaf(item1, item2));
            }

            // Find common ancestor, and each item's ancestor closest
            // to the common ancestor.
            int          item1Depth = item1.Depth;
            int          item2Depth = item2.Depth;
            GraphElement p          = item1.parent;
            GraphElement t1         = item1;

            while (item1Depth > item2Depth && p != null)
            {
                if (p == item2)
                {
                    // item2 is one of item1's ancestors; item1 is on top
                    return(t1.bStacksBehindParent);
                }
                t1 = p;
                --item1Depth;
                p = p.parent;
            }
            p = item2.parent;
            GraphElement t2 = item2;

            while (item2Depth > item1Depth && p != null)
            {
                if (p == item1)
                {
                    // item1 is one of item2's ancestors; item2 is on top
                    return(t2.bStacksBehindParent);
                }
                t2 = p;
                --item2Depth;
                p = p.parent;
            }

            // item1Ancestor is now at the same level as item2Ancestor, but not the same.
            GraphElement p1 = t1;
            GraphElement p2 = t2;

            while (t1 != null && t1 != t2)
            {
                p1 = t1;
                p2 = t2;
                t1 = t1.parent;
                t2 = t2.parent;
            }

            // in case we have a common ancestor,
            // we compare the immediate children in the ancestor's path.
            // otherwise we compare the respective items' TopLevelItems directly.
            return(ClosestLeaf(p1, p2));
        }
Example #4
0
 /// <summary>
 /// Determines whether or not <paramref name="item1"/> is on top of
 /// its sibling, <paramref name="item2"/>,
 /// based on their stacking properties, Z values, and sibling indexes.
 /// </summary>
 /// <param name="item1">The first sibling to compare.</param>
 /// <param name="item2">The second sibling to compare.</param>
 /// <returns>true if <paramref name="item1"/> is on top of
 /// <paramref name="item2"/>, false otherwise.</returns>
 public static bool ClosestLeaf(GraphElement item1, GraphElement item2)
 {
     if (item1.bStacksBehindParent != item2.bStacksBehindParent)
     {
         return(item2.bStacksBehindParent);
     }
     if (item1.z != item2.z)
     {
         return(item1.z > item2.z);
     }
     return(item1.siblingIndex > item2.siblingIndex);
 }
Example #5
0
        private void RemoveChild(GraphElement child)
        {
            // When removing elements in the middle of the children list,
            // there will be a "gap" in the list of sibling indexes (0,1,3,4).
            if (!this.holesInSiblingIndex)
            {
                this.holesInSiblingIndex
                    = child.siblingIndex != this.childCount - 1;
            }
            if (this.sequentialOrdering && !this.holesInSiblingIndex)
            {
                //this.children.RemoveAt(child.siblingIndex);
                this.childCount--;
                Array.Copy(this.children, child.siblingIndex + 1,
                           this.children, child.siblingIndex,
                           this.childCount - child.siblingIndex);
                this.children[this.childCount] = null;
            }
            else
            {
                //this.children.Remove(child);
                int i;
                for (i = 0; i < this.childCount; i++)
                {
                    if (this.children[i] == child)
                    {
                        break;
                    }
                }
                if (i < this.childCount)
                {
                    this.childCount--;
                    Array.Copy(this.children, i + 1,
                               this.children, i, this.childCount - i);
                    this.children[this.childCount] = null;
                }
            }
            // NB! Do not use children.RemoveAt(child.siblingIndex) because
            // the child is not guaranteed to be at the index after the list is sorted.
            // (see ensureSortedChildren()).
            child.siblingIndex = -1;

            this.OnChildRemoved(child);
            System.Drawing.RectangleF invalid = child.ChildrenBoundingBox();
            invalid.Offset(child.X, child.Y);
            this.Invalidate(invalid);
        }
Example #6
0
        /// <summary>
        /// Sets this element's <see cref="Parent"/> element. If
        /// <paramref name="parent"/> is null, this element gains
        /// special meaning as a "scene". </summary>
        /// <param name="parent">The new parent of this element.</param>
        /// <returns>True if this element's <see cref="Parent"/> was
        /// successfully set to <paramref name="parent"/>, false otherwise.
        /// </returns>
        public bool SetParent(GraphElement parent)
        {
            // TODO: Insert pre-notification (with possible adjustment?)

            if (parent == this)
            {
                Debug.WriteLine("Warning: Cannot assign object as a parent of itself");
                return(false);
            }
            if (parent == this.parent)
            {
                return(false);
            }

            this.OnParentChanging(parent);

            // Remove from current parent
            if (this.parent != null)
            {
                this.parent.RemoveChild(this);
            }

            // Resolve depth.
            InvalidateDepthRecursively();

            GraphElement oldParent = this.parent;

            this.parent = parent;

            if (this.parent != null)
            {
                this.parent.AddChild(this);
            }

            this.OnParentChanged(oldParent);

            // TODO: Insert post-notification

            return(true);
        }
Example #7
0
        /// <summary>
        /// Tests if this object is an ancestor of <paramref name="child"/>
        /// (i.e., if this object is <paramref name="child"/>'s parent,
        /// or one of <paramref name="child"/>'s parent's ancestors).
        /// </summary>
        /// <param name="child">The potential descendant to test.</param>
        /// <returns>true if this object is an ancestor of
        /// <paramref name="child"/>, false otherwise.</returns>
        public bool IsAncestorOf(GraphElement child)
        {
            if (child == null || child == this)
            {
                return(false);
            }
            if (child.Depth < this.Depth)
            {
                return(false);
            }
            GraphElement ancestor = child.parent;

            while (ancestor != null)
            {
                if (ancestor == this)
                {
                    return(true);
                }
                ancestor = ancestor.parent;
            }
            return(false);
        }
Example #8
0
 /// <summary>
 /// Reimplement this function to trigger events and other reactions
 /// that occur after this element's <see cref="Parent"/> has changed
 /// and after it has been removed from the
 /// <paramref name="oldParent"/>'s <see cref="Children"/> list.
 /// </summary>
 /// <param name="oldParent">The old <see cref="Parent"/>
 /// of this element.</param>
 protected virtual void OnParentChanged(GraphElement oldParent)
 {
 }
Example #9
0
 /// <summary>
 /// Reimplement this function to trigger events and other reactions
 /// that occur before this element's <see cref="Parent"/> changes to
 /// <paramref name="newParent"/> and before it's removed from its
 /// <see cref="Parent"/>'s <see cref="Children"/> list.
 /// </summary>
 /// <param name="newParent">The new <see cref="Parent"/>
 /// of this element.</param>
 protected virtual void OnParentChanging(GraphElement newParent)
 {
 }
Example #10
0
 /// <summary>
 /// Reimplement this function to trigger events and other reactions
 /// that occur after the given <paramref name="child"/> has been removed
 /// from this element's <see cref="Children"/> and before this element
 /// is invalidated over the <paramref name="child"/>'s
 /// <see cref="BoundingBox"/> offset by its <see cref="Position"/>.
 /// </summary>
 /// <param name="child">The <see cref="GraphElement"/> that has just
 /// been removed from this element's <see cref="Children"/>. </param>
 protected virtual void OnChildRemoved(GraphElement child)
 {
 }
Example #11
0
 /// <summary>
 /// Reimplement this function to trigger events and other reactions
 /// that occur after the given <paramref name="child"/> has been added
 /// to this element's <see cref="Children"/> and before this element
 /// is invalidated over the <paramref name="child"/>'s
 /// <see cref="BoundingBox"/> offset by its <see cref="Position"/>.
 /// </summary>
 /// <param name="child">The <see cref="GraphElement"/> that has just
 /// been added to this element's <see cref="Children"/>. </param>
 protected virtual void OnChildAdded(GraphElement child)
 {
 }
Example #12
0
        /// <summary>
        /// Stacks this object before <paramref name="sibling"/>, which must be a sibling object
        /// (i.e., the two objects must share the same parent, or must both be toplevel objects).
        /// The <paramref name="sibling"/> must have the same Z value as this object,
        /// otherwise calling this function will have no effect.
        /// </summary>
        /// <param name="sibling">The sibling behind which this object is stacked.</param>
        /// <returns>false if <paramref name="sibling"/> is not actually a sibling
        /// of this object, true otherwise.</returns>
        /// <remarks>
        /// By default, all sibling items are stacked by insertion order
        /// (i.e., the first item you add is drawn before the next item you add).
        /// If two items' Z values are different, then the item with the highest Z value is drawn on top.
        /// When the Z values are the same, the insertion order will decide the stacking order.
        /// </remarks>
        public bool StackBefore(GraphElement sibling)
        {
            if (sibling == this)
            {
                return(false);
            }
            if (sibling == null || this.parent != sibling.parent)
            {
                Debug.WriteLine("Warning: Cannot stack under given object, which must be a sibling");
                return(false);
            }
            int siblingCount = this.parent != null
                ? this.parent.childCount : -1;

            GraphElement[] siblings = this.parent != null
                ? this.parent.children : null;
            //(this.scene != null ? this.scene.TopLevelItems : null);
            if (siblings == null)
            {
                Debug.WriteLine("Warning: Cannot stack under given object, which must be a sibling");
                return(false);
            }

            // First, make sure that the sibling indexes have no holes.
            // This also marks the children list for sorting.
            if (this.parent != null)
            {
                this.parent.EnsureSequentialSiblingIndex();
            }
            //else
            //    this.scene.ensureSequentialTopLevelSiblingIndexes();

            int i, index;
            // Only move items with the same Z value, and that need moving.
            int siblingIndex = sibling.siblingIndex;
            int myIndex      = this.siblingIndex;

            if (myIndex >= siblingIndex)
            {
                //siblings.RemoveAt(myIndex);
                //siblings.Insert(siblingIndex, this);
                for (i = myIndex; i > siblingIndex; i--)
                {
                    siblings[i] = siblings[i - 1];
                }
                siblings[siblingIndex] = this;
                // Fixup the insertion ordering.
                for (i = 0; i < siblingCount; i++)
                {
                    index = siblings[i].siblingIndex;
                    if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
                    {
                        siblings[i].siblingIndex = ++index;
                    }
                }
                this.siblingIndex = siblingIndex;

                /*for (i = 0; i < siblings.Count; i++)
                 * {
                 *  index = siblings[i].siblingIndex;
                 *  if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
                 *      siblings[i].siblingOrderChange();
                 * }
                 * this.siblingOrderChange();/**/
            }
            return(true);
        }
Example #13
0
 /// <summary>
 /// Removes the given <paramref name="item"/> and all its children
 /// from this scene by setting the <paramref name="item"/>'s
 /// <see cref="GraphElement.Parent"/> to null (and thereby making
 /// that item its own scene in certain aspects).
 /// </summary>
 /// <param name="item">The <see cref="GraphElement"/> to remove from
 /// this scene by setting its parent to null.</param>
 public void RemoveItem(GraphElement item)
 {
     item.SetParent(null);
 }
Example #14
0
 /// <summary>
 /// Adds or moves the given <paramref name="item"/> and all its
 /// children to this scene by setting this scene as the
 /// <paramref name="item"/>'s <see cref="GraphElement.Parent"/>.
 /// </summary>
 /// <param name="item">The <see cref="GraphElement"/> to add to
 /// this scene by making this scene its parent.</param>
 public void AddItem(GraphElement item)
 {
     item.SetParent(this);
 }