// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Perspex.Input
{
///
/// Defines extensions for the interface.
///
public static class InputExtensions
{
///
/// Returns the active input elements at a point on an .
///
/// The element to test.
/// The point on .
///
/// The active input elements found at the point, ordered topmost first.
///
public static IEnumerable GetInputElementsAt(this IInputElement element, Point p)
{
Contract.Requires(element != null);
if (element.Bounds.Contains(p) &&
element.IsVisible &&
element.IsHitTestVisible &&
element.IsEnabledCore)
{
p -= element.Bounds.Position;
if (element.VisualChildren.Any())
{
foreach (var child in ZSort(element.VisualChildren.OfType()))
{
foreach (var result in child.GetInputElementsAt(p))
{
yield return result;
}
}
}
yield return element;
}
}
///
/// Returns the topmost active input element at a point on an .
///
/// The element to test.
/// The point on .
/// The topmost at the specified position.
public static IInputElement InputHitTest(this IInputElement element, Point p)
{
return element.GetInputElementsAt(p).FirstOrDefault();
}
private static IEnumerable ZSort(IEnumerable elements)
{
return elements
.Select((element, index) => new ZOrderElement
{
Element = element,
Index = index,
ZIndex = element.ZIndex,
})
.OrderBy(x => x, null)
.Select(x => x.Element);
}
private class ZOrderElement : IComparable
{
public IInputElement Element { get; set; }
public int Index { get; set; }
public int ZIndex { get; set; }
public int CompareTo(ZOrderElement other)
{
var z = other.ZIndex - ZIndex;
if (z != 0)
{
return z;
}
else
{
return other.Index - Index;
}
}
}
}
}