/// <summary> /// Compute the offset to use in determining the position of a label. /// </summary> /// <param name="elt">the label being positioned, either a child element of the <see cref="LinkPanel"/> /// or the <see cref="Part.VisualElement"/> of a label <see cref="Node"/></param> /// <param name="index">the segment of the link, or a negative value if the label should be at the <see cref="Route.MidPoint"/></param> /// <param name="segangle">the angle of the <paramref name="index"/>th segment, or the <see cref="Route.MidAngle"/></param> /// <param name="sz">the size of the label</param> /// <param name="labelangle">the angle at which the label is rotated, from calling <see cref="ComputeAngle"/></param> /// <returns>an offset that is rotated according to the angle of the segment; /// this will be added to the midpoint of the link or to the fractional point along the segment</returns> protected virtual Point ComputeOffset(UIElement elt, int index, double segangle, Size sz, double labelangle) { Point off = GetOffset(elt); Spot align = GetAlignment(elt); if (align.IsNoSpot) { align = Spot.Center; } Point p = align.PointInRect(new Rect(0, 0, sz.Width, sz.Height)); if (Double.IsNaN(off.X)) { if (index >= 0) { off.X = p.X + 3; } else { off.X = -(p.X + 3); } } if (Double.IsNaN(off.Y)) { //?? make this smarter to handle short end segments, especially if Orthogonal off.Y = -(p.Y + 3); } //?? make this better for larger non-square/circular labels that are not rotated return(Geo.RotatePoint(off, segangle)); }
private Size actualSize; // remember between MeasureAuto and ArrangeAuto /// <summary> /// Arranges the children according to the rules defined by NodePanelSizing.Auto. /// Resizes the first shape to fit around the other children and wraps text appropriately if requested. /// </summary> /// <param name="finalSize"></param> /// <returns></returns> private Size ArrangeAuto(Size finalSize) { finalSize = actualSize; Rect outer = new Rect(0, 0, finalSize.Width, finalSize.Height); Rect inner = outer; bool first = true; foreach (UIElement child in this.Children) { Part.ClearCachedValues(child); if (first) // first child is the background { first = false; child.Arrange(outer); Spot spot1 = ComputeSpot1(child); Spot spot2 = ComputeSpot2(child); inner = new Rect(spot1.PointInRect(outer), spot2.PointInRect(outer)); //Diagram.Debug("NodePanel arrange1: " + Diagram.Str(outer) + Diagram.Str(inner)); } else { child.Arrange(inner); } } return(finalSize); }
/// <summary> /// Measures the children according to the rules defined by NodePanelSizing.Fixed. /// </summary> /// <param name="finalSize"></param> /// <returns></returns> private Size ArrangeFixed(Size finalSize) { bool first = true; Rect outer = new Rect(0, 0, finalSize.Width, finalSize.Height); Rect inner = outer; foreach (UIElement child in this.Children) { Part.ClearCachedValues(child); if (finalSize == new Size(0, 0)) { child.Arrange(outer); continue; } //??? if (first) { first = false; Spot spot1 = ComputeSpot1(child); Spot spot2 = ComputeSpot2(child); inner = new Rect(spot1.PointInRect(outer), spot2.PointInRect(outer)); child.Arrange(outer); } else // Alignments are auto-accounted for, so just arrange in whatever rect is given { Rect r = inner; // adjust R according to each child's HorizontalAlignment and VerticalAlignment FrameworkElement elt = child as FrameworkElement; if (elt != null) { Size sz = EffectiveDesiredSize(child); if (sz.Width < inner.Width) { switch (elt.HorizontalAlignment) { case HorizontalAlignment.Left: r.Width = sz.Width; r.X = inner.X; break; case HorizontalAlignment.Center: r.Width = sz.Width; r.X = inner.X + inner.Width / 2 - sz.Width / 2; break; case HorizontalAlignment.Right: r.Width = sz.Width; r.X = inner.X + inner.Width - sz.Width; break; default: // Stretch means use full inner.Width break; } } if (sz.Height < inner.Height) { switch (elt.VerticalAlignment) { case VerticalAlignment.Top: r.Height = sz.Height; r.Y = inner.Y; break; case VerticalAlignment.Center: r.Height = sz.Height; r.Y = inner.Y + inner.Height / 2 - sz.Height / 2; break; case VerticalAlignment.Bottom: r.Height = sz.Height; r.Y = inner.Y + inner.Height - sz.Height; break; default: // Stretch means use full inner.Height break; } } } child.Arrange(r); } } return(finalSize); }