/// <summary> /// Insert a row in the visual tree. /// </summary> private void InsertRow(DiagramRow row) { if (row != null && row.NodeCount > 0) { this.AddVisualChild(row); rows.Insert(0, row); } }
/// <summary> /// Add the siblings to the specified row and group. /// </summary> private void AddSiblingNodes(DiagramRow row, DiagramGroup group, Collection <Shape> siblings, NodeType nodeType, double scale) { foreach (Shape sibling in siblings) { if (!personLookup.ContainsKey(sibling)) { // Siblings node. DiagramNode node = CreateNode(sibling, nodeType, true, scale); group.Add(node); personLookup.Add(node.Shape, new DiagramConnectorNode(node, group, row)); } } }
/// <summary> /// Creates the primary row. The row contains groups: 1) The primary-group /// that only contains the primary node, and 2) The optional left-group /// that contains spouses and siblings. /// </summary> public DiagramRow CreatePrimaryRow(Shape person, double scale, double scaleRelated) { // The primary node contains two groups, DiagramGroup primaryGroup = new DiagramGroup(); DiagramGroup leftGroup = new DiagramGroup(); // Set up the row. DiagramRow row = new DiagramRow(); // Add primary node. DiagramNode node = CreateNode(person, NodeType.Primary, false, scale); primaryGroup.Add(node); personLookup.Add(node.Shape, new DiagramConnectorNode(node, primaryGroup, row)); // Current spouses. Collection <Shape> currentSpouses = person.CurrentSpouses; AddSpouseNodes(person, row, leftGroup, currentSpouses, NodeType.Spouse, scaleRelated, true); // Previous spouses. Collection <Shape> previousSpouses = person.PreviousSpouses; AddSpouseNodes(person, row, leftGroup, previousSpouses, NodeType.Spouse, scaleRelated, false); // Siblings. Collection <Shape> siblings = person.Siblings; AddSiblingNodes(row, leftGroup, siblings, NodeType.Sibling, scaleRelated); // Half siblings. Collection <Shape> halfSiblings = person.HalfSiblings; AddSiblingNodes(row, leftGroup, halfSiblings, NodeType.SiblingLeft, scaleRelated); if (leftGroup.Nodes.Count > 0) { leftGroup.Reverse(); row.Add(leftGroup); } row.Add(primaryGroup); return(row); }
/// <summary> /// Return list of people in the row that are primary or related node types. /// </summary> private static List <Shape> GetPrimaryAndRelatedPeople(DiagramRow row) { List <Shape> list = new List <Shape>(); foreach (DiagramGroup group in row.Groups) { foreach (DiagramNode node in group.Nodes) { if (node.Type == NodeType.Related || node.Type == NodeType.Primary) { list.Add(node.Shape); } } } return(list); }
/// <summary> /// Add a parent row to the diagram. /// </summary> private DiagramRow AddParentRow(DiagramRow row, double nodeScale) { // Get list of parents for the current row. Collection <DrawStructure.Main.Shape> parents = DiagramLogic.GetParents(row); if (parents.Count == 0) { return(null); } // Add another row. DiagramRow parentRow = logic.CreateParentRow(parents, nodeScale, nodeScale * Const.RelatedMultiplier); parentRow.Margin = new Thickness(0, 0, 0, Const.RowSpace); parentRow.GroupSpace = Const.ParentRowGroupSpace; InsertRow(parentRow); return(parentRow); }
/// <summary> /// Add the spouses to the specified row and group. /// </summary> private void AddSpouseNodes(Shape person, DiagramRow row, DiagramGroup group, Collection <Shape> spouses, NodeType nodeType, double scale, bool married) { foreach (Shape spouse in spouses) { if (!personLookup.ContainsKey(spouse)) { // Spouse node. DiagramNode node = CreateNode(spouse, nodeType, true, scale); group.Add(node); // Add connection. DiagramConnectorNode connectorNode = new DiagramConnectorNode(node, group, row); personLookup.Add(node.Shape, connectorNode); connections.Add(new MarriedDiagramConnector(married, personLookup[person], connectorNode)); } } }
/// <summary> /// Add a child row to the diagram. /// </summary> private DiagramRow AddChildRow(DiagramRow row) { // Get list of children for the current row. List <DrawStructure.Main.Shape> children = DiagramLogic.GetChildren(row); if (children.Count == 0) { return(null); } // Add bottom space to existing row. row.Margin = new Thickness(0, 0, 0, Const.RowSpace); // Add another row. DiagramRow childRow = logic.CreateChildrenRow(children, 1.0, Const.RelatedMultiplier); childRow.GroupSpace = Const.ChildRowGroupSpace; AddRow(childRow); return(childRow); }
/// <summary> /// Return a list of parents for the people in the specified row. /// </summary> /// <param name="row"></param> /// <returns></returns> public static Collection <Shape> GetParents(DiagramRow row) { // List that is returned. Collection <Shape> list = new Collection <Shape>(); // Get possible children in the row. List <Shape> rowList = GetPrimaryAndRelatedPeople(row); // Add each parent to the list, make sure the parent is only added once. foreach (Shape person in rowList) { foreach (Shape parent in person.Parents) { if (!list.Contains(parent)) { list.Add(parent); } } } return(list); }
/// <summary> /// Return a list of children for the people in the specified row. /// </summary> public static List <Shape> GetChildren(DiagramRow row) { // List that is returned. List <Shape> list = new List <Shape>(); // Get possible parents in the row. List <Shape> rowList = GetPrimaryAndRelatedPeople(row); // Add each child to the list, make sure the child is only added once. foreach (Shape person in rowList) { foreach (Shape child in person.Children) { if (!list.Contains(child)) { list.Add(child); } } } return(list); }
/// <summary> /// Create the child row. The row contains a group for each child. /// Each group contains the child and spouses. /// </summary> public DiagramRow CreateChildrenRow(List <Shape> children, double scale, double scaleRelated) { // Setup the row. DiagramRow row = new DiagramRow(); foreach (Shape child in children) { // Each child is in their group, the group contains the child // and any spouses. The groups does not contain siblings. DiagramGroup group = new DiagramGroup(); row.Add(group); // Child. if (!personLookup.ContainsKey(child)) { DiagramNode node = CreateNode(child, NodeType.Related, true, scale); group.Add(node); personLookup.Add(node.Shape, new DiagramConnectorNode(node, group, row)); } // Current spouses. Collection <Shape> currentSpouses = child.CurrentSpouses; AddSpouseNodes(child, row, group, currentSpouses, NodeType.Spouse, scaleRelated, true); // Previous spouses. Collection <Shape> previousSpouses = child.PreviousSpouses; AddSpouseNodes(child, row, group, previousSpouses, NodeType.Spouse, scaleRelated, false); // Connections. AddParentConnections(child); group.Reverse(); } return(row); }
/// <summary> /// Reset the diagram with the nodes. This is accomplished by creating a series of rows. /// Each row contains a series of groups, and each group contains the nodes. The elements /// are not laid out at this time. Also creates the connections between the nodes. /// </summary> private void UpdateDiagram() { // Necessary for Blend. if (logic.Family == null) { return; } // First reset everything. Clear(); // Nothing to draw if there is not a primary person. if (logic.Family.Current == null) { return; } // Primary row. DrawStructure.Main.Shape primaryPerson = logic.Family.Current; DiagramRow primaryRow = logic.CreatePrimaryRow(primaryPerson, 1.0, Const.RelatedMultiplier); primaryRow.GroupSpace = Const.PrimaryRowGroupSpace; AddRow(primaryRow); // Create as many rows as possible until exceed the max node limit. // Switch between child and parent rows to prevent only creating // child or parents rows (want to create as many of each as possible). int nodeCount = this.NodeCount; // The scale values of future generations, this makes the nodes // in each row slightly smaller. double nodeScale = 1.0; DiagramRow childRow = primaryRow; DiagramRow parentRow = primaryRow; while (nodeCount < Const.MaximumNodes && (childRow != null || parentRow != null)) { // Child Row. if (childRow != null) { childRow = AddChildRow(childRow); } // Parent row. if (parentRow != null) { nodeScale *= Const.GenerationMultiplier; parentRow = AddParentRow(parentRow, nodeScale); } // See if reached node limit yet. nodeCount = this.NodeCount; } // Raise event so others know the diagram was updated. OnDiagramUpdated(); // Animate the new person (optional, might not be any new people). AnimateNewPerson(); }
public DiagramConnectorNode(DiagramNode node, DiagramGroup group, DiagramRow row) { this.node = node; this.group = group; this.row = row; }
/// <summary> /// Create the parent row. The row contains a group for each parent. /// Each groups contains the parent, spouses and siblings. /// </summary> public DiagramRow CreateParentRow(Collection <Shape> parents, double scale, double scaleRelated) { // Set up the row. DiagramRow row = new DiagramRow(); int groupCount = 0; foreach (Shape person in parents) { // Each parent is in their group, the group contains the parent, // spouses and siblings. DiagramGroup group = new DiagramGroup(); row.Add(group); // Determine if this is a left or right oriented group. bool left = (groupCount++ % 2 == 0) ? true : false; // Parent. if (!personLookup.ContainsKey(person)) { DiagramNode node = CreateNode(person, NodeType.Related, true, scale); group.Add(node); personLookup.Add(node.Shape, new DiagramConnectorNode(node, group, row)); } // Current spouses. Collection <Shape> currentSpouses = person.CurrentSpouses; RemoveDuplicates(currentSpouses, parents); AddSpouseNodes(person, row, group, currentSpouses, NodeType.Spouse, scaleRelated, true); // Previous spouses. Collection <Shape> previousSpouses = person.PreviousSpouses; RemoveDuplicates(previousSpouses, parents); AddSpouseNodes(person, row, group, previousSpouses, NodeType.Spouse, scaleRelated, false); // Siblings. Collection <Shape> siblings = person.Siblings; AddSiblingNodes(row, group, siblings, NodeType.Sibling, scaleRelated); // Half siblings. Collection <Shape> halfSiblings = person.HalfSiblings; AddSiblingNodes(row, group, halfSiblings, left ? NodeType.SiblingLeft : NodeType.SiblingRight, scaleRelated); // Connections. AddChildConnections(person); AddChildConnections(currentSpouses); AddChildConnections(previousSpouses); if (left) { group.Reverse(); } } // Add connections that span across groups. AddSpouseConnections(parents); return(row); }