public void TestGetLowestCommonAncestor() { DomNodeType type = new DomNodeType("type"); ChildInfo childInfo = new ChildInfo("child", type, true); type.Define(childInfo); DomNode parent = new DomNode(type); DomNode child1 = new DomNode(type); DomNode child2 = new DomNode(type); parent.GetChildList(childInfo).Add(child1); parent.GetChildList(childInfo).Add(child2); DomNode grandchild1 = new DomNode(type); child1.GetChildList(childInfo).Add(grandchild1); DomNode grandchild2 = new DomNode(type); child2.GetChildList(childInfo).Add(grandchild2); Assert.AreSame(DomNode.GetLowestCommonAncestor(child1, child2), parent); Assert.AreSame(DomNode.GetLowestCommonAncestor(grandchild1, grandchild2), parent); Assert.AreSame(DomNode.GetLowestCommonAncestor(child1, grandchild1), child1); Assert.AreSame(DomNode.GetLowestCommonAncestor(new DomNode[] { child1, child2, grandchild1 }), parent); }
// an element is eligible to move into another container only it first moves out its current container private bool IsSelfContainedOrIntersected(DomNode element, DomNode container) { // the moving element should first move out of the parent container next to the common ancestor var commonAncestor = DomNode.GetLowestCommonAncestor(element, container); var currentContainer = element.Lineage.First(x => x.Parent == commonAncestor); if (element == currentContainer) { return(false); // no self containing } var control = m_viewingContext.Cast <AdaptableControl>(); var elemLocalBound = GetLocalBound(control, element.Cast <Element>()); var containerLocalBound = GetLocalBound(control, currentContainer.Cast <Element>()); containerLocalBound.Location = new PointF(0, GetTitleHeight(control)); containerLocalBound.Height -= GetLabelHeight(control);// exclude bottom label area elemLocalBound.Offset(GetSubContentOffset(control)); bool contained = containerLocalBound.Contains(elemLocalBound); containerLocalBound.Height -= GetTitleHeight(control);// no subcontent offset if element is moved out of the current container bool intersected = containerLocalBound.IntersectsWith(elemLocalBound); return(contained || intersected); }
/// Gets location offset from oldContainer to newContainer, compensate renderer displacements for element title /// and margin sub-nodes location are defined relative to the parent container private Point GetRelativeOffset(ICircuitContainer oldContainer, ICircuitContainer newContainer) { AdaptableControl control = m_viewingContext.Cast <AdaptableControl>(); var offset = new Point(); var oldDomContainer = oldContainer.Cast <DomNode>(); var newDomContainer = newContainer.Cast <DomNode>(); var commonAncestor = DomNode.GetLowestCommonAncestor(oldDomContainer, newDomContainer); var upPath = oldDomContainer.Lineage.TakeWhile(x => x != commonAncestor); var upOffset = GetWorldOffset(control, upPath.AsIEnumerable <Element>()); offset.Offset(upOffset.X, upOffset.Y); var downPath = newDomContainer.Lineage.TakeWhile(x => x != commonAncestor).Reverse(); var downOffset = GetWorldOffset(control, downPath.AsIEnumerable <Element>()); offset.Offset(-downOffset.X, -downOffset.Y); return(offset); }
// update edge routes private void UpdateWires(IEnumerable <ICircuitContainer> containers) { foreach (var container in containers) { foreach (var wire in container.Wires.ToArray()) { //string edgeName = CircuitUtil.GetDomNodeName(wire.DomNode); bool input = container.Elements.Contains(wire.InputElement); bool output = container.Elements.Contains(wire.OutputElement); if (input && output) // still an internal edge of the container (not a container-crossing link) { if (wire.InputElement.Type is MissingElementType || wire.OutputElement.Type is MissingElementType) { continue; // skip wires connected to missing types } var matchedInput = new Pair <Element, ICircuitPin>(); foreach (var module in container.Elements) { matchedInput = module.FullyMatchPinTarget(wire.InputPinTarget, true); if (matchedInput.First != null) { break; } } var matchedOutput = new Pair <Element, ICircuitPin>(); foreach (var module in container.Elements) { matchedOutput = module.FullyMatchPinTarget(wire.OutputPinTarget, false); if (matchedOutput.First != null) { break; } } if (matchedInput.First != null && matchedOutput.First != null) { wire.InputElement = matchedInput.First; wire.InputPin = matchedInput.Second; Debug.Assert(matchedOutput.First != null); wire.OutputElement = matchedOutput.First; wire.OutputPin = matchedOutput.Second; continue; } } if (MovingCrossContainer) { var leafNodeIn = wire.InputPinTarget.InstancingNode ?? wire.InputPinTarget.LeafDomNode; var leafNodeOut = wire.OutputPinTarget.InstancingNode ?? wire.OutputPinTarget.LeafDomNode; var newParent = DomNode.GetLowestCommonAncestor(leafNodeIn, leafNodeOut); if (newParent == null) { continue; } var newParentContainer = newParent.Cast <ICircuitContainer>(); var matchedInput = newParentContainer.FullyMatchPinTarget(wire.InputPinTarget, true); Debug.Assert(matchedInput.First != null); var matchedOutput = newParentContainer.FullyMatchPinTarget(wire.OutputPinTarget, false); Debug.Assert(matchedOutput.First != null); if (newParentContainer.Is <Group>()) // the edge should connect to child nodes of the parent container { var grpPin = matchedInput.Second.Cast <GroupPin>(); wire.InputElement = grpPin.InternalElement; wire.InputPin = grpPin.InternalElement.AllInputPins.ElementAt(grpPin.InternalPinIndex); } else { wire.InputElement = matchedInput.First; wire.InputPin = matchedInput.Second; } if (newParentContainer.Is <Group>()) { var grpPin = matchedOutput.Second.Cast <GroupPin>(); wire.OutputElement = grpPin.InternalElement; wire.OutputPin = grpPin.InternalElement.AllOutputPins.ElementAt(grpPin.InternalPinIndex); } else { wire.OutputElement = matchedOutput.First; wire.OutputPin = matchedOutput.Second; } if (container != newParentContainer) { container.Wires.Remove(wire); newParentContainer.Wires.Add(wire); } } else { // the edge has invalid route, must be caused by nodes deletion down the container hierarchy container.Wires.Remove(wire); } } } }