/// <summary> /// Helper function that indicates if given collection is the root. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <returns></returns> public virtual bool IsRootCollection(TreeControl tc, NodeCollection nc) { return(tc.Nodes == nc); }
/// <summary> /// Process a left mouse down on the Node instance. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <param name="n">Reference to Node within collection.</param> /// <param name="pt">Point being pressed down.</param> /// <returns>true if the point was processed; otherwise false.</returns> public virtual bool DoubleClick(TreeControl tc, NodeCollection nc, Node n, Point pt) { // Not processed return(false); }
/// <summary> /// Draw the NodeCollection instance. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <param name="g">Reference to Graphics instance to draw into.</param> /// <param name="clipRectangle">Clipping rectangle used when drawing.</param> /// <param name="preDraw">True when drawing before children and fales for drawing after.</param> public virtual void Draw(TreeControl tc, NodeCollection nc, Graphics g, Rectangle clipRectangle, bool preDraw) { if (preDraw) { // Only draw lines and boxes if there is at least one child node if (nc.VisibleCount > 0) { // Find out if lines and boxes needed drawing bool showLines = ShowLines(tc, nc); bool showBoxes = ShowBoxes(tc, nc); bool showIndicators = (IsRootCollection(tc, nc) && (tc.Indicators != Indicators.None)) || (!IsRootCollection(tc, nc) && (tc.Indicators == Indicators.AtGroup)); // Is there any drawing to perform? if (showLines || showBoxes || showIndicators) { Pen lineDashPen = tc.GetCacheLineDashPen(); // Cache the whole rectangle used for drawing Rectangle ncBounds = nc.Cache.Bounds; // Find the size of space taken up with indicators Size indicatorSize = showIndicators ? tc.IndicatorSize : Size.Empty; // Perform any adjustment for drawing within the bounds AdjustBeforeDrawing(tc, nc, ref ncBounds); // Cache the mid and right hand side of the lines column int xMid = ncBounds.Left + indicatorSize.Width + (tc.ColumnWidth / 2) - 1; int xRight = ncBounds.Left + indicatorSize.Width + tc.ColumnWidth; // Need to adjust drawing child connecting lines, so that wider than one // pixel pens start from left of vertical for top and bottom children, but // are placed to the right of middle children. int xMidAdjustL = xMid - (tc.LineWidth / 2); int xMidAdjustR = xMid + 1; // Find the first and last visible nodes int firstVisible = nc.FirstVisibleIndex; int lastVisible = nc.LastVisibleIndex; // Find the first and last nodes mid points int yMidFirst = nc[firstVisible].Cache.Bounds.Top + (nc[firstVisible].Cache.Bounds.Height / 2); int yMidLast = nc[lastVisible].Cache.Bounds.Top + (nc[lastVisible].Cache.Bounds.Height / 2); // No point drawing line after end of clipping rectangle if (yMidLast > clipRectangle.Bottom) { yMidLast = clipRectangle.Bottom; } // Do we need to draw the long vertical line? if (showLines) { // Draw the long vertical line down the middle if (IsRootCollection(tc, nc)) { // No point drawing line before start of clipping rectangle if (yMidFirst < clipRectangle.Top) { yMidFirst = clipRectangle.Top; // Adjust starting point up so dot/dash lines are consistent switch (tc.LineDashStyle) { case LineDashStyle.Dot: yMidFirst -= yMidFirst % (2 * tc.LineWidth); break; case LineDashStyle.Dash: yMidFirst -= yMidFirst % (4 * tc.LineWidth); break; } } // We are root collection, so draw from the first node to the last g.DrawLine(lineDashPen, xMid, yMidFirst, xMid, yMidLast); } else { // Not at root, so draw from top of column to the last node g.DrawLine(lineDashPen, xMid, ncBounds.Top, xMid, yMidLast); } } // Process each child node in turn, drawing horizontal line and any box for (int i = nc.ChildFromY(clipRectangle.Top); i < nc.Count; i++) { if (DrawNode(tc, nc[i], g, clipRectangle, showLines, showBoxes, showIndicators, (i == 0) || (i == (nc.Count - 1)), lineDashPen, xMidAdjustL, xMidAdjustR, xMid, xRight, ncBounds.Left)) { break; } } } } } }
/// <summary> /// Adjust the total bounds of the collection into the bounds available for drawing. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <param name="ncBounds">Drawing bounds to draw within.</param> public virtual void AdjustBeforeDrawing(TreeControl tc, NodeCollection nc, ref Rectangle ncBounds) { // By default we having no changes to make }
/// <summary> /// Find if the provided rectangle intersects the bounds of the node collection. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <param name="rectangle">Rectangle to compare against.</param> /// <returns>True if intersecting; otherwise false.</returns> public virtual bool IntersectsWith(TreeControl tc, NodeCollection nc, Rectangle rectangle) { return(nc.Cache.Bounds.IntersectsWith(rectangle)); }
/// <summary> /// Defines the bounding rectangle of the collection. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <param name="bounds">Bounding rectangle of collection.</param> public virtual void SetBounds(TreeControl tc, NodeCollection nc, Rectangle bounds) { // Update cache bounds using new value nc.Cache.Bounds = bounds; }
private void SynchronizeCollections(NodeCollection orig, NodeCollection copy, ITypeDescriptorContext context) { // Make a note of all original nodes that are still in copy Hashtable both = new Hashtable(); // First pass, scan looking for nodes that are in original and copy foreach (Node copyChild in copy) { // Does this node have an back pointer to its original? if (copyChild.Original != null) { // Then make a note that it is in both collections both.Add(copyChild.Original, copyChild.Original); // Update the original from the copy copyChild.Original.UpdateInstance(copyChild); } } int origCount = orig.Count; // Second pass, remove nodes in the original but not in the copy for (int i = 0; i < origCount; i++) { // Get access to the indexed node from original Node origChild = orig[i]; // If not in the found collection... if (!both.ContainsKey(origChild)) { // ...then it has been removed from the copy, so delete it orig.Remove(origChild); // Must remove from context container so it is removed from designer tray context.Container.Remove(origChild as IComponent); // Reduce the count and index to reflect change in collection contents --i; --origCount; } } int copyCount = copy.Count; // Third pass, add new nodes from copy but not in original for (int i = 0; i < copyCount; i++) { // Get access to the indexed node from copy Node copyChild = copy[i]; // If this node is a new one then it will not have an 'original' property if (copyChild.Original == null) { // Add this node into the original at indexed position orig.Insert(i, copyChild); // Must add into context container so it is added to the designer tray context.Container.Add(copyChild as IComponent); } } // Fourth pass, process all children foreach (Node copyChild in copy) { // Does this node has an back pointer to its original? if (copyChild.Original != null) { // Recurse down into the child collections SynchronizeCollections(copyChild.Original.Nodes, copyChild.Nodes, context); } } }
/// <summary> /// Helper function that indicates if given collection is the root. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <returns></returns> public override bool IsRootCollection(TreeControl tc, NodeCollection nc) { return((nc.ParentNode != null) && (nc.ParentNode.ParentNodes == tc.Nodes)); }
/// <summary> /// Draw the NodeCollection instance. /// </summary> /// <param name="tc">Reference to owning TreeControl.</param> /// <param name="nc">Reference to NodeCollection instance.</param> /// <param name="g">Reference to Graphics instance to draw into.</param> /// <param name="clipRectangle">Clipping rectangle used when drawing.</param> /// <param name="preDraw">True when drawing before children and fales for drawing after.</param> public override void Draw(TreeControl tc, NodeCollection nc, Graphics g, Rectangle clipRectangle, bool preDraw) { // The real root never has anything to draw if (!IsRealRootCollection(tc, nc)) { // Let base class do its stuff base.Draw(tc, nc, g, clipRectangle, preDraw); // Only draw the extra separating lines and image column after children are drawn if (!preDraw) { // The root within each group might have something to do if (IsRootCollection(tc, nc)) { // Do we need to account for the image box column? if (tc.GroupImageBox && tc.GroupImageBoxColumn) { // Recover the actual control drawing area in node space Rectangle drawRect = tc.ClientToNodeSpace(tc.DrawRectangle); // Get the bounding rectangle of the collection Rectangle ncBounds = nc.Cache.Bounds; // If this the first visible collection bool firstVisibleCollection = (ncBounds.Top <= drawRect.Top) && (ncBounds.Bottom >= drawRect.Top); // Adjust backwards to account for group indent ncBounds.X -= tc.GroupIndentLeft; // Adjust to just the image column width ncBounds.Width = tc.GroupImageBoxWidth; // Draw the image column color g.FillRectangle(tc.GetCacheGroupImageBoxColumnBrush(), ncBounds); // Draw the separator line on right hand side of column g.DrawLine(tc.GetCacheGroupImageBoxLinePen(), ncBounds.Right, ncBounds.Top, ncBounds.Right, ncBounds.Bottom - 1); // We draw top and bottom collection separators, if we have no border if (tc.BorderStyle == TreeBorderStyle.None) { // Draw the separator line on right side of control g.DrawLine(tc.GetCacheGroupImageBoxLinePen(), drawRect.Right - 1, ncBounds.Top, drawRect.Right - 1, ncBounds.Bottom - 1); // The first collection drawn on the control... if (firstVisibleCollection) { // ...needs a top line separator g.DrawLine(tc.GetCacheGroupImageBoxLinePen(), ncBounds.Right, drawRect.Top, drawRect.Right - 1, drawRect.Top); } bool lastSibling = true; // Then search siblings... for (int i = nc.ParentNode.Index + 1; i < nc.ParentNode.ParentNodes.Count; i++) { Node next = nc.ParentNode.ParentNodes[i]; // For a node that is visible... if (next.Visible) { lastSibling = false; break; } } // If the last sibling, or collection runs off end of control if (lastSibling || (ncBounds.Bottom > drawRect.Bottom)) { // Find the bottom line for drawing int bottom = ncBounds.Bottom - 1; // If we party run off end of the control the use end of control instead if (bottom >= drawRect.Bottom) { bottom = drawRect.Bottom - 1; } // ...then draw separator line at bottom of collection g.DrawLine(tc.GetCacheGroupImageBoxLinePen(), ncBounds.Right, bottom, drawRect.Right - 1, bottom); } } } } } } }