Rectangle LayoutSubTopics(Topic parent, Topic[] subTopics, Vector4 vector, XList <int> rows, XList <int> columns, int parentRow, int parentCol, MindMapLayoutArgs e) { if (parent == null) { throw new ArgumentNullException(); } if (rows.IsEmpty || columns.IsEmpty) { return(Rectangle.Empty); } if (parent.Folded || parent.Children.IsEmpty) { return(Rectangle.Empty); } int vSpace = e.ItemsSpace; Topic root = parent.GetRoot(); Rectangle rectFull = Rectangle.Empty; Point pp = PaintHelper.CenterPoint(root.ContentBounds); int fullHeight = GetYPos(rows.Count - 1, vSpace, rows); int x = vector == Vector4.Left ? root.Left - e.LayerSpace : root.Right + e.LayerSpace; int y = pp.Y - (fullHeight / 2) - 30; int hSpace = 10; Topic previous = parent == root ? root : parent.ParentTopic; int prevRow = 0; for (int i = 0, n = subTopics.Length; i < n; ++i) { Topic subTopic = subTopics[i]; subTopic.Vector = vector; int row = 0, column = 0; switch (vector) { case Vector4.Top: subTopic.Location = new Point(root.Bounds.Left - (subTopic.Width - root.Width) / 2, parent.Location.Y - e.LayerSpace - subTopic.Size.Height); break; case Vector4.Left: case Vector4.Right: default: if (subTopic.Type == TopicType.Barrier) { column = parentCol - subTopics.Length + i; row = parentRow; } else { column = parentCol + (subTopic.Folded ? 0 : subTopic.Children.Count) + 1; row = parentRow + 1; if (subTopic.Type == TopicType.Escalation) { int maxUncleRow = 0; if (parent.ParentTopic != null) { XList <Topic> children = parent.ParentTopic.Children; int nextIndex = children.IndexOf(parent) + 1; if (nextIndex < children.Count) { maxUncleRow = CalculateMaxRow(children[nextIndex], children.ToArray()); } } int maxSiblingRow = 0; int prevIndex = i - 1; if (prevIndex >= 0) { maxSiblingRow = CalculateMaxRow(parent.Children[prevIndex], parent.Children.ToArray()); } row += maxSiblingRow + maxUncleRow; } else if (parent.IsRoot) { int prevIndex = i - 1; if (prevIndex >= 0) { row += CalculateMaxRow(subTopics[prevIndex], subTopics); } } } Point pt = new Point(GetXPos(column, hSpace, columns, vector), GetYPos(row, vSpace, rows)); if (subTopic.Type == TopicType.Barrier) { if (vector == Vector4.Left) { pt.X -= (subTopic.ContentBounds.Width - subTopic.Width) / 2; } else { pt.X += (subTopic.ContentBounds.Width - subTopic.Width) / 2; } } subTopic.Location = new Point(vector == Vector4.Left ? x - pt.X: x + pt.X, pt.Y + y); prevRow = row; break; } // line if (!parent.Folded && subTopic.Type == TopicType.Barrier) { var lines = CreateTopicLines(e, previous, subTopic, vector, GetReverseVector(vector)); if (lines != null) { parent.Lines.AddRange(lines); } } subTopic.Lines.Clear(); Rectangle rectFullSub = LayoutSubTopics(subTopic, subTopic.Children.ToArray(), vector, rows, columns, row, column, e); // Threat topic will be drawn as the last element if (subTopic.Type == TopicType.Threat || subTopic.Type == TopicType.Consequence || subTopic.Type == TopicType.Escalation) { Topic beginNode, endNode; if (subTopic.HasChildren && !subTopic.Folded) { beginNode = subTopic.Children[subTopic.Children.Count - 1]; endNode = subTopic; } else { beginNode = parent; endNode = subTopic; } var lines = CreateTopicLines(e, beginNode, endNode, vector, GetReverseVector(vector)); if (lines != null) { beginNode.Lines.AddRange(lines); } if (subTopic.HasChildren) { int foldBtnSize = FoldingButtonSize; if (vector == Vector4.Left) { subTopic.FoldingButton = new Rectangle(subTopic.Right - foldBtnSize + 4, subTopic.Top + (int)Math.Round((60 - foldBtnSize) / 2.0f, MidpointRounding.AwayFromZero), foldBtnSize, foldBtnSize); } else if (vector == Vector4.Right) { subTopic.FoldingButton = new Rectangle(subTopic.Left - foldBtnSize + 4, subTopic.Top + (int)Math.Round((60 - foldBtnSize) / 2.0f, MidpointRounding.AwayFromZero), foldBtnSize, foldBtnSize); } } } else if (subTopic.Type == TopicType.Hazard) { var lines = CreateTopicLines(e, root, subTopic, vector, GetReverseVector(vector)); if (lines != null) { root.Lines.AddRange(lines); } } rectFull = Rectangle.Union(rectFull, subTopic.ContentBounds); if (!rectFullSub.IsEmpty) { rectFull = Rectangle.Union(rectFull, rectFullSub); } previous = subTopic; } return(rectFull); }