private LayoutShape GetRoot(LayoutShape mostRelatives) { LayoutShape root = mostRelatives; if (root == null) { // Get the node in the diagram that is not a fact type or external constraint LayoutShape first = null; foreach (LayoutShape layshape in myLayoutShapes) { if (!layshape.Placed) { if (first == null) { first = layshape; } if (!(layshape.Shape is FactTypeShape) && !(layshape.Shape is ExternalConstraintShape)) { root = layshape; break; } } } // either they're all fact type shapes, or we only found one node if (root == null) { root = first; } } return(root); }
/// <summary> /// This method ensures that the role in the related fact type is closest (spatially) to the related object shape. /// </summary> /// <param name="shape">The shape that was most recently placed on the diagram</param> protected override void PostShapePlacement(LayoutShape shape) { FactTypeShape factShape; LayoutShape parentShape; if (shape.Pinned || null == (parentShape = shape.Parent) || null == (factShape = shape.Shape as FactTypeShape)) { return; } NodeShape objectShape = parentShape.Shape; ModelElement objectElement = parentShape.Shape.ModelElement; FactType factElement; if (null != (factElement = objectElement as FactType)) { Objectification objectification = factElement.Objectification; if (objectification != null) { objectElement = objectification.NestingType; } } factElement = factShape.ModelElement as FactType; LinkedElementCollection <RoleBase> roles = factShape.DisplayedRoleOrder; // set the index at which the role will be closest to otherLayoutShape int targetIndex = 0; LayoutShape objectLayoutShape; PointD objectShapeLocation = myLayoutShapes.TryGetValue(objectShape, out objectLayoutShape) ? objectLayoutShape.TargetLocation : objectShape.Location; SizeD objectShapeSize = objectShape.Size; objectShapeLocation.Offset(objectShapeSize.Width / 2, objectShapeSize.Height / 2); if (objectShapeLocation.X > shape.TargetLocation.X + (factShape.Size.Width / 2)) { targetIndex = roles.Count - 1; } // find actual index bool haveEditableOrder = false; int roleCount = roles.Count; for (int i = 0; i < roleCount; ++i) { if (roles[i].Role.RolePlayer == objectElement) { if (i == targetIndex) { if (!haveEditableOrder) { haveEditableOrder = true; roles = factShape.GetEditableDisplayRoleOrder(); } roles.Move(i, targetIndex); break; } } } }
/// <summary> /// Perform pre-layout tasks /// </summary> protected override void PreLayout() { // Separate out the external constraint shapes for (int i = myLayoutShapes.Count - 1; i >= 0; --i) { LayoutShape layshape = myLayoutShapes[i]; if (layshape.Shape is ExternalConstraintShape) { myConstraintShapes.Add(layshape); myLayoutShapes.RemoveAt(i); } } }
/// <summary> /// Resolves references between shapes (indicated as lines on the diagram) /// </summary> /// <param name="list">Any list of <seealso cref="LayoutShape"/>s that need to have the shape references resolved</param> /// <returns>The shape with the most references in the list (typically treated as the root shape)</returns> /// <remarks>Any <see cref="LayoutShape"/> where the <see cref="LayoutShape.Placed"/> property is <see langword="true"/> /// should be ignored.</remarks> public override LayoutShape ResolveReferences(LayoutShapeList list) { LayoutShape mostChildren = null; LayoutShapeList allShapes = myLayoutShapes; foreach (LayoutShape layshape in list) { if (!layshape.Placed) { layshape.ResolveReferences(allShapes); if ((mostChildren == null || layshape.Count > mostChildren.Count) && !(layshape.Shape is FactTypeShape) && !(layshape.Shape is ExternalConstraintShape)) { mostChildren = layshape; } } } return(mostChildren); }
/// <summary> /// Adds the <paramref name="shape"/> with the specified <paramref name="pinned"/> value. /// </summary> /// <param name="shape">The shape to lay out on the diagram.</param> /// <param name="pinned">Indicates whether the shape is pinned in place or not. True means the shape is pinned to its current location.</param> public void AddShape(ShapeElement shape, bool pinned) { NodeShape ns = shape as NodeShape; if (ns == null || shape.ParentShape as ORMDiagram == null) { return; } LayoutShapeList list = myLayoutShapes; LayoutShape layshape; // If the shape doesn't exist, add it, otherwise simply modify the pinned value. if (!list.TryGetValue(ns, out layshape)) { layshape = new LayoutShape(ns, pinned); list.Add(layshape); } else { layshape.Pinned = pinned; } }
/// <summary> /// This method ensures that the role in the related fact type is closest (spatially) to the related object shape. /// </summary> /// <param name="shape">The shape that was most recently placed on the diagram</param> protected override void PostShapePlacement(LayoutShape shape) { FactTypeShape factShape; LayoutShape parentShape; if (shape.Pinned || null == (parentShape = shape.Parent) || null == (factShape = shape.Shape as FactTypeShape)) { return; } NodeShape objectShape = parentShape.Shape; ModelElement objectElement = parentShape.Shape.ModelElement; FactType factElement; if (null != (factElement = objectElement as FactType)) { Objectification objectification = factElement.Objectification; if (objectification != null) { objectElement = objectification.NestingType; } } factElement = factShape.ModelElement as FactType; LinkedElementCollection<RoleBase> roles = factShape.DisplayedRoleOrder; // set the index at which the role will be closest to otherLayoutShape int targetIndex = 0; LayoutShape objectLayoutShape; PointD objectShapeLocation = myLayoutShapes.TryGetValue(objectShape, out objectLayoutShape) ? objectLayoutShape.TargetLocation : objectShape.Location; SizeD objectShapeSize = objectShape.Size; objectShapeLocation.Offset(objectShapeSize.Width / 2, objectShapeSize.Height / 2); if (objectShapeLocation.X > shape.TargetLocation.X + (factShape.Size.Width / 2)) { targetIndex = roles.Count - 1; } // find actual index bool haveEditableOrder = false; int roleCount = roles.Count; for (int i = 0; i < roleCount; ++i) { if (roles[i].Role.RolePlayer == objectElement) { if (i == targetIndex) { if (!haveEditableOrder) { haveEditableOrder = true; roles = factShape.GetEditableDisplayRoleOrder(); } roles.Move(i, targetIndex); break; } } } }
/// <summary> /// Organizes the shapes added with <see cref="AddShape(ShapeElement)"/> or similar methods. /// </summary> /// <param name="ignoreExistingShapes">Do not adjust for existing shapes</param> /// <param name="referenceShape">Layout shapes to the right of this shape.</param> /// <param name="layoutRightOfReferenceShape">Set to layout to the right of the <paramref name="referenceShape"/></param> /// <param name="layoutBelowReferenceShape">Set to layout below the <paramref name="referenceShape"/></param> public void Layout(bool ignoreExistingShapes, NodeShape referenceShape, bool layoutRightOfReferenceShape, bool layoutBelowReferenceShape) { LayoutShape backupRoot = null; LayoutShapeList allShapes = myLayoutShapes; switch (allShapes.Count) { case 0: return; default: backupRoot = allShapes[0]; break; } myLayoutEngine.LateBind(myDiagram, allShapes); SizeD margin = myDiagram.NestedShapesMargin; if (referenceShape != null && (layoutRightOfReferenceShape || layoutBelowReferenceShape)) { RectangleD referenceBounds = referenceShape.AbsoluteBounds; if (layoutRightOfReferenceShape) { margin.Width = Math.Max(margin.Width, referenceBounds.Right); } if (layoutBelowReferenceShape) { margin.Height = Math.Max(margin.Height, referenceBounds.Bottom); } } PointD minimumPoint = new PointD(margin.Width, margin.Height); RectangleD layoutRectangle = new RectangleD(minimumPoint, SizeD.Empty); bool firstPass = true; for (; ;) { LayoutShape mostRelatives = myLayoutEngine.ResolveReferences(allShapes); LayoutShape root = null; // If the root shape was set by the user, AND the shape exists in our shape list if (myRootShape == null || !allShapes.TryGetValue(myRootShape, out root)) { root = GetRoot(mostRelatives); } if (root == null) { if (backupRoot == null) { myLayoutEngine.PostLayout(minimumPoint); break; } root = backupRoot; } // run the layout of base shapes myLayoutEngine.PerformLayout(root, new PointD(margin.Width, layoutRectangle.Bottom + (firstPass ? 0 : root.Shape.Size.Height)), ref layoutRectangle); firstPass = false; backupRoot = null; myRootShape = null; } Reflow(ignoreExistingShapes); }
private LayoutShape GetRoot(LayoutShape mostRelatives) { LayoutShape root = mostRelatives; if (root == null) { // Get the node in the diagram that is not a fact type or external constraint LayoutShape first = null; foreach (LayoutShape layshape in myLayoutShapes) { if (!layshape.Placed) { if (first == null) { first = layshape; } if (!(layshape.Shape is FactTypeShape) && !(layshape.Shape is ExternalConstraintShape)) { root = layshape; break; } } } // either they're all fact type shapes, or we only found one node if (root == null) { root = first; } } return root; }
/// <summary> /// Places each external constraint shape at the point corresponding to the average of all of its referenced shapes. /// Frequency constraints are handled differently, since they apply to only one fact type (but 1 or more roles in that /// fact type) at any time. /// </summary> /// <param name="minimumPoint">The minimum location for new element placement</param> public override void PostLayout(PointD minimumPoint) { ResolveReferences(myConstraintShapes); foreach (LayoutShape shape in myConstraintShapes) { if (!shape.Pinned) { PointD avg = new PointD(0, 0); NodeShape nodeShape = shape.Shape; FrequencyConstraintShape freqShape; FrequencyConstraint constraint; LinkedElementCollection <FactType> relatedFactTypes; int count; if (null != (freqShape = nodeShape as FrequencyConstraintShape) && null != (constraint = freqShape.ModelElement as FrequencyConstraint) && 1 == (relatedFactTypes = constraint.FactTypeCollection).Count) { Diagram diagram = myDiagram; FactType factType = relatedFactTypes[0]; FactTypeShape factTypeShape = null; LayoutShape factTypeLayoutShape = null; foreach (PresentationElement pel in PresentationViewsSubject.GetPresentation(factType)) { FactTypeShape testShape = pel as FactTypeShape; if (testShape != null && testShape.Diagram == diagram) { if (factTypeShape == null) { factTypeShape = testShape; } if (myLayoutShapes.TryGetValue(testShape, out factTypeLayoutShape)) { factTypeShape = testShape; break; } } } LinkedElementCollection <Role> constraintRoles = constraint.RoleCollection; LinkedElementCollection <RoleBase> displayOrder = factTypeShape.DisplayedRoleOrder; DisplayOrientation orientation = factTypeShape.DisplayOrientation; RectangleD shapeBounds = factTypeShape.AbsoluteBounds; SizeD shapeSize = factTypeShape.Size; PointD location = (factTypeLayoutShape != null) ? factTypeLayoutShape.TargetLocation : shapeBounds.Location; count = constraintRoles.Count; double width = shapeSize.Width; double height = shapeSize.Height; for (int i = 0; i < count; i++) { int targetIndex = displayOrder.IndexOf(constraintRoles[i]); switch (orientation) { case DisplayOrientation.Horizontal: avg.Offset((width / (targetIndex + 1)) + location.X, location.Y - height); break; case DisplayOrientation.VerticalRotatedRight: avg.Offset(location.X + width, (height / (targetIndex + 1)) + location.Y); break; case DisplayOrientation.VerticalRotatedLeft: avg.Offset(location.X + width, height - (height / (targetIndex + 1)) + location.Y); break; } } avg.X /= count; avg.Y /= count; } else if (0 != (count = shape.Count)) { double minX = double.MaxValue; double minY = double.MaxValue; double maxX = 0; double maxY = 0; SizeD size; LayoutShapeList relatedShapes = shape.RelatedShapes; // Take the center of farthest bounds as the location. // This is the same as the average for two elements, but // balances more than two elements much better. for (int i = 0; i < count; ++i) { LayoutShape relatedShape = relatedShapes[i]; PointD location = relatedShape.TargetLocation; size = relatedShape.Shape.Size; double x = location.X + size.Width / 2; double y = location.Y + size.Height / 2; minX = Math.Min(minX, x); minY = Math.Min(minY, y); maxX = Math.Max(maxX, x); maxY = Math.Max(maxY, y); } size = nodeShape.Size; avg.X = (maxX + minX) / 2 - size.Width / 2; avg.Y = (maxY + minY) / 2 - size.Height / 2; // Constraints are frequently ending up directly on top of // an ObjectTypeShape, bump them up a bit double bumpAdjust = size.Height * 2; avg.Y -= bumpAdjust; if (avg.Y < minimumPoint.Y) { avg.Y += bumpAdjust + bumpAdjust; } } shape.TargetLocation = avg; } shape.Placed = true; } // Now add the shapes back into the main myLayoutShape list for reflow foreach (LayoutShape shape in myConstraintShapes) { myLayoutShapes.Add(shape); } myConstraintShapes.Clear(); }
private LayoutPlaceholder(P.PlaceholderShape pPlaceholderShape, LayoutShape layoutShape) : base(pPlaceholderShape) { BaseShape = new ResettableLazy <Shape>(() => layoutShape.SlideLayout.SlideMaster.Shapes.GetShapeByPPlaceholderShape(pPlaceholderShape)); }
/// <summary> /// Creates placeholder. Returns <c>NULL</c> if the specified shape is not placeholder. /// </summary> internal static LayoutPlaceholder Create(OpenXmlCompositeElement pShapeTreeChild, LayoutShape slideShape) { P.PlaceholderShape pPlaceholderShape = pShapeTreeChild.ApplicationNonVisualDrawingProperties().GetFirstChild <P.PlaceholderShape>(); if (pPlaceholderShape == null) { return(null); } return(new LayoutPlaceholder(pPlaceholderShape, slideShape)); }