/// <summary> /// Compute the rectangle in which the elements should be positioned. /// </summary> /// <returns> /// If this panel is in an <see cref="Adornment"/> and is its <see cref="Node.LocationElement"/>, /// return the <see cref="Adornment.AdornedElement"/>'s size. /// Otherwise return a <c>Rect</c> based on this first child's <c>DesiredSize</c>. /// Only the Width and Height of the Rect matter in the calculations performed by /// <see cref="MeasureOverride"/> and <see cref="ArrangeOverride"/>. /// </returns> protected virtual Rect ComputeBorder() { Adornment ad = Diagram.FindAncestor <Adornment>(this); if (ad != null) { FrameworkElement elt = ad.AdornedElement; if (elt != null && this == ad.LocationElement) { Size sz = ad.GetEffectiveSize(elt); if (sz.Width > 0 && sz.Height > 0) { return(new Rect(0, 0, sz.Width, sz.Height)); } } } Size s = this.DesiredSize; foreach (UIElement child in this.Children) { s = child.DesiredSize; break; } return(new Rect(0, 0, s.Width, s.Height)); }
// Return a Geometry that has points that are scaled up to the size of the ADORNED element. //?? hack: EXCEPT in Silverlight, where if the AdornedElement is a Path/Polygon/Polyline, the Geometry might not have absolute points, // but will need to be stretched by the ADORNMENT Shape. internal static Geometry GetSelectionGeometry(Shape adorning, Adornment ad) { FrameworkElement adorned = ad.AdornedElement; Part adornedpart = ad.AdornedPart; Shape shape = adorned as Shape; if (shape != null) { return(GetRenderedGeometry(shape, ad)); } // otherwise just assume it's rectangular // Try to surround the adorned element by accounting for the thickness of the adornment's stroke // as well as the actual size of the adorned element. double t = (adorning != null ? adorning.StrokeThickness : 0); Size sz = new Size(0, 0); if (adornedpart != null) { sz = adornedpart.GetEffectiveSize(adorned); // can't just use ActualWidth/Height, because measuring has reset them to zero } return(new RectangleGeometry() { Rect = new Rect(-t / 2, -t / 2, sz.Width + t, sz.Height + t) }); }
/// <summary> /// Arrange the child elements of this panel and of any label nodes. /// </summary> /// <param name="finalSize"></param> /// <returns></returns> /// <remarks> /// This positions each child element based on the attached property values of /// <see cref="GetIndex"/>, <see cref="GetFraction"/>, <see cref="GetAlignment"/>, /// and <see cref="GetOrientation"/>. /// This also positions any <see cref="Link.LabelNode"/>, /// using the <see cref="LinkPanel"/> attached properties on the node's <see cref="Part.VisualElement"/>, /// even though such a node is not within the visual tree of this panel. /// If the label node is a <see cref="Group"/>, this will instead position all of the /// group's <see cref="Group.MemberNodes"/>. /// </remarks> protected override Size ArrangeOverride(Size finalSize) { Part part = Diagram.FindAncestor <Part>(this); if (part == null) { return(new Size()); } Link link = part as Link; if (link == null) { Adornment node = part as Adornment; if (node != null) { link = node.AdornedPart as Link; } } if (link != null) { //Diagram.Debug(" LinkPanelA- " + (link.Data != null ? link.Data.ToString() : "")); Shape stroke = this.Path; // may be null Route route = link.Route; Rect routeBounds = route.RouteBounds; IList <Point> pts = (List <Point>)route.Points; int nPoints = pts.Count; int childidx = 0; if (stroke != null) { if (childidx < childrenBounds.Count) { stroke.Arrange(childrenBounds[childidx++]); } } foreach (UIElement e in this.Children) { if (e == stroke) { continue; } if (childidx < childrenBounds.Count) { //if (e.GetType().Name.Contains("Expander")) Diagram.Debug(e.ToString() + " arranged: " + Diagram.Str(childrenBounds[childidx])); e.Arrange(childrenBounds[childidx++]); } } //Diagram.Debug(" LinkPanelA+ " + (link.Data != null ? link.Data.ToString() : "")); Node label = link.LabelNode; if (label != null) { Group labelgroup = label as Group; foreach (Node m in (labelgroup != null ? labelgroup.MemberNodes : new Node[1] { label })) { if (nPoints < 2) { continue; } UIElement e = m.VisualElement; Size sz = new Size(m.Bounds.Width, m.Bounds.Height); int index = GetIndex(e); double frac = ComputeFraction(GetFraction(e)); Spot align = GetAlignment(e); if (align.IsNoSpot) { align = Spot.Center; } LabelOrientation orient = GetOrientation(e); Point nodept; // model coordinates if (index < -nPoints || index >= nPoints) // beyond range? assume at the MidPoint, with the MidAngle { Point mid = route.MidPoint; double segangle = route.MidAngle; // maybe rotate the label double labelangle = 0; if (orient != LabelOrientation.None) { labelangle = ComputeAngle(e, orient, segangle); m.SetAngle(e, labelangle, align); } // maybe the alignment point is away from the line nodept = mid; // model coordinates Point offset = ComputeOffset(e, index, segangle, sz, labelangle); nodept = Geo.Add(nodept, offset); } else // on a particular segment, given by Index, at a point given by Fraction // negative index means start from last point, going "backwards" { Point a, b; if (index >= 0) { a = pts[index]; b = (index < nPoints - 1) ? pts[index + 1] : a; } else { int i = nPoints + index; // remember that index is negative here a = pts[i]; b = (i > 0) ? pts[i - 1] : a; } // compute the fractional point along the line, in model coordinates nodept = new Point(a.X + (b.X - a.X) * frac, a.Y + (b.Y - a.Y) * frac); double segangle = (index >= 0 ? Geo.GetAngle(a, b) : Geo.GetAngle(b, a)); // maybe rotate the label double labelangle = 0; if (orient != LabelOrientation.None) { labelangle = ComputeAngle(e, orient, segangle); m.SetAngle(e, labelangle, align); } // maybe the alignment point is away from the line Point offset = ComputeOffset(e, index, segangle, sz, labelangle); nodept = Geo.Add(nodept, offset); } Rect hb = align.RectForPoint(nodept, sz); m.Position = new Point(hb.X, hb.Y); } } } return(finalSize); }
/// <summary> /// Determine the size of the union of the bounds of the positioned and rotated child elements. /// </summary> /// <param name="availableSize"></param> /// <returns></returns> protected override Size MeasureOverride(Size availableSize) { Part part = Diagram.FindAncestor <Part>(this); if (part == null) { return(new Size()); } if (!part.IsMeasuringArranging) { return(new Size()); } Link link = part as Link; if (link == null) { Adornment ad = part as Adornment; if (ad != null) { link = ad.AdornedPart as Link; } if (link == null) { return(new Size()); } } //Diagram.Debug(" LinkPanelM- " + (link.Data != null ? link.Data.ToString() : "")); Shape stroke = this.Path; // may be null link.Path = stroke; // the Link caches what the Path really is Route route = link.Route; Rect routeBounds = route.RouteBounds; // in model coordinates Rect linkBounds = routeBounds; // includes all labels childrenBounds = new List <Rect>(); // in local coordinates if (stroke != null) { stroke.Measure(Geo.Unlimited); Size sz = stroke.DesiredSize; linkBounds.Width = Math.Max(linkBounds.Width, sz.Width); linkBounds.Height = Math.Max(linkBounds.Height, sz.Height); childrenBounds.Add(new Rect(0, 0, linkBounds.Width, linkBounds.Height)); } IList <Point> pts = (List <Point>)route.Points; int nPoints = pts.Count; foreach (UIElement e in this.Children) { if (e == stroke) { continue; // already measured the stroke, above } e.Measure(Geo.Unlimited); //if (e.GetType().Name.Contains("Expander")) Diagram.Debug(e.ToString() + " measured: " + Diagram.Str(e.DesiredSize)); if (nPoints < 2) { continue; } Size sz = e.DesiredSize; int index = GetIndex(e); double frac = ComputeFraction(GetFraction(e)); Spot align = GetAlignment(e); if (align.IsNoSpot) { align = Spot.Center; } LabelOrientation orient = GetOrientation(e); Point eltpt; // local coordinates if (index < -nPoints || index >= nPoints) // beyond range? assume at the MidPoint, with the MidAngle { Point mid = route.MidPoint; if (this.Implementation == LinkPanelImplementation.Stretch) { Point p0 = pts[0]; Point pn = pts[nPoints - 1]; sz.Width = Math.Sqrt(Geo.DistanceSquared(pn, p0)); } double segangle = route.MidAngle; // maybe rotate the label double labelangle = 0; if (orient != LabelOrientation.None) { labelangle = ComputeAngle(e, orient, segangle); link.SetAngle(e, labelangle, align); } // maybe the alignment point is away from the line eltpt = new Point(mid.X - routeBounds.X, mid.Y - routeBounds.Y); // local coordinates Point offset = ComputeOffset(e, index, segangle, sz, labelangle); eltpt = Geo.Add(eltpt, offset); } else // on a particular segment, given by Index, at a point given by Fraction // negative index means start from last point, going "backwards" { Point a, b; if (index >= 0) { a = pts[index]; b = (index < nPoints - 1) ? pts[index + 1] : a; } else { int i = nPoints + index; // remember that index is negative here a = pts[i]; b = (i > 0) ? pts[i - 1] : a; } // compute the fractional point along the line, in local coordinates eltpt = new Point(a.X + (b.X - a.X) * frac - routeBounds.X, a.Y + (b.Y - a.Y) * frac - routeBounds.Y); double segangle = (index >= 0 ? Geo.GetAngle(a, b) : Geo.GetAngle(b, a)); // maybe rotate the label double labelangle = 0; if (orient != LabelOrientation.None) { labelangle = ComputeAngle(e, orient, segangle); link.SetAngle(e, labelangle, align); } // maybe the alignment point is away from the line Point offset = ComputeOffset(e, index, segangle, sz, labelangle); eltpt = Geo.Add(eltpt, offset); } Rect cb = align.RectForPoint(eltpt, sz); childrenBounds.Add(cb); // local coordinates linkBounds.Union(new Rect(cb.X + routeBounds.X, cb.Y + routeBounds.Y, cb.Width, cb.Height)); // model coordinates } // if this panel is the "whole" link, update the link's Bounds if (link.VisualElement == this) { //Diagram.Debug(" LinkPanelM+ " + (link.Data != null ? link.Data.ToString() : "") + " " + Diagram.Str(routeBounds) + Diagram.Str(linkBounds)); link.Bounds = new Rect(routeBounds.X, routeBounds.Y, linkBounds.Width, linkBounds.Height); } return(new Size(routeBounds.Width, routeBounds.Height)); }
private static Geometry GetRenderedGeometry(Shape shape, Adornment ad) { Rectangle rectangle = shape as Rectangle; if (rectangle != null) { Size sz = ad.GetEffectiveSize(rectangle); return(new RectangleGeometry() { Rect = new Rect(0, 0, sz.Width, sz.Height), RadiusX = rectangle.RadiusX, RadiusY = rectangle.RadiusY }); } Ellipse ellipse = shape as Ellipse; if (ellipse != null) { Size sz = ad.GetEffectiveSize(ellipse); return(new EllipseGeometry() { Center = new Point(sz.Width / 2, sz.Height / 2), RadiusX = sz.Width / 2, RadiusY = sz.Height / 2 }); } Line line = shape as Line; if (line != null) { return new LineGeometry() { StartPoint = new Point(line.X1, line.Y1), EndPoint = new Point(line.X2, line.Y2) } } ; Polyline polyline = shape as Polyline; if (polyline != null) { PathGeometry g = new PathGeometry(); PathFigure pf = new PathFigure(); PolyLineSegment pls = new PolyLineSegment(); pls.Points = Copy(polyline.Points); //?? not returning a Geometry with the actual points if (polyline.Stretch != Stretch.None) { Size sz = ad.GetEffectiveSize(polyline); pls.Points = ScalePoints(pls.Points, sz, polyline.Stretch); } pf.Segments.Add(pls); if (pls.Points.Count > 0) { pf.StartPoint = pls.Points[0]; } pf.IsClosed = false; pf.IsFilled = false; g.Figures.Add(pf); return(g); } Polygon polygon = shape as Polygon; if (polygon != null) { PathGeometry g = new PathGeometry(); PathFigure pf = new PathFigure(); PolyLineSegment pls = new PolyLineSegment(); pls.Points = Copy(polygon.Points); //?? not returning a Geometry with the actual points if (polygon.Stretch != Stretch.None) { Size sz = ad.GetEffectiveSize(polygon); pls.Points = ScalePoints(pls.Points, sz, polygon.Stretch); } pf.Segments.Add(pls); if (pls.Points.Count > 0) { pf.StartPoint = pls.Points[0]; } pf.IsClosed = true; pf.IsFilled = true; g.Figures.Add(pf); return(g); } Path path = shape as Path; if (path != null) { return(Copy(path.Data)); //?? not returning a Geometry with the actual points } return(null); }
// Return a Geometry that has points that are scaled up to the size of the ADORNED element. //?? hack: EXCEPT in Silverlight, where if the AdornedElement is a Path/Polygon/Polyline, the Geometry might not have absolute points, // but will need to be stretched by the ADORNMENT Shape. internal static Geometry GetSelectionGeometry(Shape adorning, Adornment ad) { FrameworkElement adorned = ad.AdornedElement; Part adornedpart = ad.AdornedPart; Shape shape = adorned as Shape; if (shape != null) return GetRenderedGeometry(shape, ad); // otherwise just assume it's rectangular // Try to surround the adorned element by accounting for the thickness of the adornment's stroke // as well as the actual size of the adorned element. double t = (adorning != null ? adorning.StrokeThickness : 0); Size sz = new Size(0, 0); if (adornedpart != null) { sz = adornedpart.GetEffectiveSize(adorned); // can't just use ActualWidth/Height, because measuring has reset them to zero } return new RectangleGeometry() { Rect = new Rect(-t/2, -t/2, sz.Width+t, sz.Height+t) }; }
private static Geometry GetRenderedGeometry(Shape shape, Adornment ad) { Rectangle rectangle = shape as Rectangle; if (rectangle != null) { Size sz = ad.GetEffectiveSize(rectangle); return new RectangleGeometry() { Rect = new Rect(0, 0, sz.Width, sz.Height), RadiusX = rectangle.RadiusX, RadiusY = rectangle.RadiusY }; } Ellipse ellipse = shape as Ellipse; if (ellipse != null) { Size sz = ad.GetEffectiveSize(ellipse); return new EllipseGeometry() { Center = new Point(sz.Width/2, sz.Height/2), RadiusX = sz.Width/2, RadiusY = sz.Height/2 }; } Line line = shape as Line; if (line != null) return new LineGeometry() { StartPoint = new Point(line.X1, line.Y1), EndPoint = new Point(line.X2, line.Y2) }; Polyline polyline = shape as Polyline; if (polyline != null) { PathGeometry g = new PathGeometry(); PathFigure pf = new PathFigure(); PolyLineSegment pls = new PolyLineSegment(); pls.Points = Copy(polyline.Points); //?? not returning a Geometry with the actual points if (polyline.Stretch != Stretch.None) { Size sz = ad.GetEffectiveSize(polyline); pls.Points = ScalePoints(pls.Points, sz, polyline.Stretch); } pf.Segments.Add(pls); if (pls.Points.Count > 0) pf.StartPoint = pls.Points[0]; pf.IsClosed = false; pf.IsFilled = false; g.Figures.Add(pf); return g; } Polygon polygon = shape as Polygon; if (polygon != null) { PathGeometry g = new PathGeometry(); PathFigure pf = new PathFigure(); PolyLineSegment pls = new PolyLineSegment(); pls.Points = Copy(polygon.Points); //?? not returning a Geometry with the actual points if (polygon.Stretch != Stretch.None) { Size sz = ad.GetEffectiveSize(polygon); pls.Points = ScalePoints(pls.Points, sz, polygon.Stretch); } pf.Segments.Add(pls); if (pls.Points.Count > 0) pf.StartPoint = pls.Points[0]; pf.IsClosed = true; pf.IsFilled = true; g.Figures.Add(pf); return g; } Path path = shape as Path; if (path != null) return Copy(path.Data); //?? not returning a Geometry with the actual points return null; }