using System; using Avalonia.VisualTree; namespace Avalonia { /// /// Extension methods for . /// public static class VisualExtensions { /// /// Converts a point from screen to client coordinates. /// /// The visual. /// The point in screen coordinates. /// The point in client coordinates. public static Point PointToClient(this IVisual visual, PixelPoint point) { var rootPoint = visual.VisualRoot.PointToClient(point); return visual.VisualRoot.TranslatePoint(rootPoint, visual).Value; } /// /// Converts a point from client to screen coordinates. /// /// The visual. /// The point in client coordinates. /// The point in screen coordinates. public static PixelPoint PointToScreen(this IVisual visual, Point point) { var p = visual.TranslatePoint(point, visual.VisualRoot); return visual.VisualRoot.PointToScreen(p.Value); } /// /// Returns a transform that transforms the visual's coordinates into the coordinates /// of the specified . /// /// The visual whose coordinates are to be transformed. /// The visual to translate the coordinates to. /// /// A containing the transform or null if the visuals don't share a /// common ancestor. /// public static Matrix? TransformToVisual(this IVisual from, IVisual to) { var common = from.FindCommonVisualAncestor(to); if (common != null) { var thisOffset = GetOffsetFrom(common, from); var thatOffset = GetOffsetFrom(common, to); return -thatOffset * thisOffset; } return null; } /// /// Translates a point relative to this visual to coordinates that are relative to the specified visual. /// /// The visual. /// The point value, as relative to this visual. /// The visual to translate the given point into. /// /// A point value, now relative to the target visual rather than this source element, or null if the /// two elements have no common ancestor. /// public static Point? TranslatePoint(this IVisual visual, Point point, IVisual relativeTo) { var transform = visual.TransformToVisual(relativeTo); if (transform.HasValue) { return point.Transform(transform.Value); } return null; } /// /// Gets a transform from an ancestor to a descendent. /// /// The ancestor visual. /// The visual. /// The transform. private static Matrix GetOffsetFrom(IVisual ancestor, IVisual visual) { var result = Matrix.Identity; while (visual != ancestor) { if (visual.RenderTransform?.Value != null) { var origin = visual.RenderTransformOrigin.ToPixels(visual.Bounds.Size); var offset = Matrix.CreateTranslation(origin); var renderTransform = (-offset) * visual.RenderTransform.Value * (offset); result *= renderTransform; } var topLeft = visual.Bounds.TopLeft; if (topLeft != default) { result *= Matrix.CreateTranslation(topLeft); } visual = visual.VisualParent; if (visual == null) { throw new ArgumentException("'visual' is not a descendant of 'ancestor'."); } } return result; } } }