// determines whether the button has been hit public bool IsHit(IInputModeContext context, PointD location) { // see if the button is visible at all IOrientedRectangle orientedRectangle = label.GetLayout(); if (orientedRectangle.Contains(location, context.HitTestRadius)) { location = location - orientedRectangle.GetAnchorLocation(); double upX = orientedRectangle.UpX; double upY = orientedRectangle.UpY; double tx = location.X * -upY + location.Y * upX; double ty = location.X * upX + location.Y * upY; // consider auto flipping of the label contents if (upY > 0) { return (new RectD(inset, inset, 20, orientedRectangle.Height - 2 * inset).Contains(new PointD(tx, ty), context.HitTestRadius)); } else { return (new RectD(orientedRectangle.Width - (inset + buttonWidth), inset, buttonWidth, orientedRectangle.Height - 2 * inset).Contains(new PointD(tx, ty), context.HitTestRadius)); } } else { return(false); } }
/// <summary> /// Creates the geometry for the label's path. /// </summary> /// <param name="layout">The label's layout.</param> /// <param name="text">The label text.</param> /// <returns>The label path's geometry.</returns> /// <remarks> /// The label's visualization is an approximation of its text where each word is represented by a line with a length /// proportional to the word's length. In the vast majority of cases this approximates the position of spaces in the line /// accurately enough that the switch from a text label to a fast label is almost imperceptible. /// </remarks> private StreamGeometry CreateGeometry(IOrientedRectangle layout, string text) { var origin = layout.GetAnchorLocation(); var up = layout.GetUp(); var right = new PointD(-up.Y, up.X); if (AutoFlip && up.Y > 0) { origin = origin + up * layout.Height + right * layout.Width; up = -up; right = -right; } var upperLeft = origin + up * layout.Height; // This part could be optimized a bit by not allocating new objects and thus reduce pressure on the garbage // collector. However, in practice it made not much of an impact. var lines = text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var longestLineLength = lines.Max(l => l.Length); var sizePerLetter = layout.Width / longestLineLength; var geometry = new StreamGeometry(); using (var ctx = geometry.Open()) { // Fill – only drawn when a brush was set if (BackgroundBrush != null) { ctx.BeginFigure(origin, true, false); ctx.PolyLineTo(new Point[] { origin + right * layout.Width, origin + right * layout.Width + up * layout.Height, origin + up * layout.Height }, false, false); } // Lines for (int i = 0; i < lines.Length; i++) { var line = lines[i]; var words = line.Split(' ', ' '); var currentPoint = upperLeft - up * layout.Height / lines.Length * (i + 0.6); // Words foreach (var word in words) { var wordLength = word.Length * sizePerLetter; var targetPoint = currentPoint + right * wordLength; ctx.BeginFigure(currentPoint, false, false); ctx.LineTo(targetPoint, true, false); currentPoint = targetPoint + right * sizePerLetter; } } } return(geometry); }
/// <summary> /// Creates the geometry for the selection rectangle. /// </summary> /// <param name="layout">The label's layout.</param> /// <returns>The selection rectangle geometry.</returns> private Geometry CreateGeometry(IOrientedRectangle layout) { var up = layout.GetUp(); var anchor = layout.GetAnchorLocation(); var right = new PointD(-up.Y, up.X); var g = new StreamGeometry(); using (var ctx = g.Open()) { ctx.BeginFigure(anchor, Fill != null, true); ctx.LineTo(anchor + right * layout.Width, true, false); ctx.LineTo(anchor + right * layout.Width + up * layout.Height, true, false); ctx.LineTo(anchor + up * layout.Height, true, false); ctx.LineTo(anchor, true, false); } return(g); }
/// <summary> /// Returns the location of the specified position on the border of the oriented rectangle. /// </summary> private PointD GetLocation(IOrientedRectangle layout, HandlePositions position) { if (layout == null) { return(node.Layout.ToPointD()); } switch (position) { case HandlePositions.NorthWest: return(GetLocation(layout, 0.0, 1.0)); case HandlePositions.North: return(GetLocation(layout, 0.5, 1.0)); case HandlePositions.NorthEast: return(GetLocation(layout, 1.0, 1.0)); case HandlePositions.East: return(GetLocation(layout, 1.0, 0.5)); case HandlePositions.SouthEast: return(GetLocation(layout, 1.0, 0.0)); case HandlePositions.South: return(GetLocation(layout, 0.5, 0.0)); case HandlePositions.SouthWest: return(layout.GetAnchorLocation()); case HandlePositions.West: return(GetLocation(layout, 0.0, 0.5)); default: throw new ArgumentOutOfRangeException(); } }
public Visual UpdateSelectionVisual(IRenderContext context, Visual oldVisual, IOrientedRectangle layout) { var container = oldVisual as VisualGroup; if (container != null && container.Children.Count == 1) { var visual = container.Children[0] as FrameworkElement; if (visual != null) { Transform transform = context.IntermediateTransform; container.Transform = transform; var anchor = layout.GetAnchorLocation(); var anchorAndUp = anchor + layout.GetUp(); anchor = context.WorldToIntermediateCoordinates(anchor); anchorAndUp = context.WorldToIntermediateCoordinates(anchorAndUp); var or = new OrientedRectangle(); or.SetUpVector((anchorAndUp - anchor).Normalized); or.SetAnchor(anchor); or.Width = layout.Width * context.Zoom; or.Height = layout.Height * context.Zoom; visual.Width = or.Width; visual.Height = or.Height; visual.SetCanvasArrangeRect(new Rect(0, 0, or.Width, or.Height)); ArrangeByLayout(context, visual, or, false); if (!container.IsMeasureValid) { container.Arrange(new Rect(0, 0, or.Width, or.Height)); } return(container); } } return(CreateSelectionVisual(context, layout)); }