|
|
|
@ -2,7 +2,6 @@ |
|
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
|
|
|
|
|
using System; |
|
|
|
using Avalonia.Rendering; |
|
|
|
using Avalonia.VisualTree; |
|
|
|
|
|
|
|
namespace Avalonia |
|
|
|
@ -20,10 +19,8 @@ namespace Avalonia |
|
|
|
/// <returns>The point in client coordinates.</returns>
|
|
|
|
public static Point PointToClient(this IVisual visual, PixelPoint point) |
|
|
|
{ |
|
|
|
var (root, offset) = GetRootAndPosition(visual); |
|
|
|
var screenOffset = PixelPoint.FromPoint((Point)offset, root.RenderScaling); |
|
|
|
var screenPoint = new PixelPoint(point.X - screenOffset.X, point.Y - screenOffset.Y); |
|
|
|
return root.PointToClient(screenPoint); |
|
|
|
var rootPoint = visual.VisualRoot.PointToClient(point); |
|
|
|
return visual.VisualRoot.TranslatePoint(rootPoint, visual).Value; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -34,48 +31,93 @@ namespace Avalonia |
|
|
|
/// <returns>The point in screen coordinates.</returns>
|
|
|
|
public static PixelPoint PointToScreen(this IVisual visual, Point point) |
|
|
|
{ |
|
|
|
var p = GetRootAndPosition(visual); |
|
|
|
return p.Item1.PointToScreen(point + p.Item2); |
|
|
|
var p = visual.TranslatePoint(point, visual.VisualRoot); |
|
|
|
return visual.VisualRoot.PointToScreen(p.Value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns a transform that transforms the visual's coordinates into the coordinates
|
|
|
|
/// of the specified <paramref name="to"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="from">The visual whose coordinates are to be transformed.</param>
|
|
|
|
/// <param name="to">The visual to translate the coordinates to.</param>
|
|
|
|
/// <returns>
|
|
|
|
/// A <see cref="Matrix"/> containing the transform or null if the visuals don't share a
|
|
|
|
/// common ancestor.
|
|
|
|
/// </returns>
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Translates a point relative to this visual to coordinates that are relative to the specified visual.
|
|
|
|
/// The visual and relativeTo should be descendants of the same root window
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="visual">The visual.</param>
|
|
|
|
/// <param name="point">The point value, as relative to this visual.</param>
|
|
|
|
/// <param name="relativeTo">The visual to translate the given point into.</param>
|
|
|
|
/// <returns>A point value, now relative to the target visual rather than this source element.</returns>
|
|
|
|
public static Point TranslatePoint(this IVisual visual, Point point, IVisual relativeTo) |
|
|
|
/// <returns>
|
|
|
|
/// A point value, now relative to the target visual rather than this source element, or null if the
|
|
|
|
/// two elements have no common ancestor.
|
|
|
|
/// </returns>
|
|
|
|
public static Point? TranslatePoint(this IVisual visual, Point point, IVisual relativeTo) |
|
|
|
{ |
|
|
|
var pos = GetRootAndPosition(visual); |
|
|
|
var relToPos = GetRootAndPosition(relativeTo); |
|
|
|
var transform = visual.TransformToVisual(relativeTo); |
|
|
|
|
|
|
|
return point - (relToPos.Item2 - pos.Item2); |
|
|
|
if (transform.HasValue) |
|
|
|
{ |
|
|
|
return point.Transform(transform.Value); |
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the root of the control's visual tree and the position of the control
|
|
|
|
/// in the root's coordinate space.
|
|
|
|
/// Gets a transform from an ancestor to a descendent.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="v">The visual.</param>
|
|
|
|
/// <returns>A tuple containing the root and the position of the control.</returns>
|
|
|
|
private static Tuple<IRenderRoot, Vector> GetRootAndPosition(IVisual v) |
|
|
|
/// <param name="ancestor">The ancestor visual.</param>
|
|
|
|
/// <param name="visual">The visual.</param>
|
|
|
|
/// <returns>The transform.</returns>
|
|
|
|
private static Matrix GetOffsetFrom(IVisual ancestor, IVisual visual) |
|
|
|
{ |
|
|
|
var result = new Vector(); |
|
|
|
var result = Matrix.Identity; |
|
|
|
|
|
|
|
while (!(v is IRenderRoot)) |
|
|
|
while (visual != ancestor) |
|
|
|
{ |
|
|
|
result = new Vector(result.X + v.Bounds.X, result.Y + v.Bounds.Y); |
|
|
|
v = v.VisualParent; |
|
|
|
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 (v == null) |
|
|
|
if (visual == null) |
|
|
|
{ |
|
|
|
throw new InvalidOperationException("Control is not attached to visual tree."); |
|
|
|
throw new ArgumentException("'visual' is not a descendant of 'ancestor'."); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Tuple.Create((IRenderRoot)v, result); |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|