using System;
using System.Collections.Generic;
namespace Avalonia.LogicalTree
{
///
/// Provides extension methods for working with the logical tree.
///
public static class LogicalExtensions
{
///
/// Enumerates the ancestors of an in the logical tree.
///
/// The logical.
/// The logical's ancestors.
public static IEnumerable GetLogicalAncestors(this ILogical logical)
{
_ = logical ?? throw new ArgumentNullException(nameof(logical));
ILogical? l = logical.LogicalParent;
while (l != null)
{
yield return l;
l = l.LogicalParent;
}
}
///
/// Enumerates an and its ancestors in the logical tree.
///
/// The logical.
/// The logical and its ancestors.
public static IEnumerable GetSelfAndLogicalAncestors(this ILogical logical)
{
yield return logical;
foreach (var ancestor in logical.GetLogicalAncestors())
{
yield return ancestor;
}
}
///
/// Finds first ancestor of given type.
///
/// Ancestor type.
/// The logical.
/// If given logical should be included in search.
/// First ancestor of given type.
public static T? FindLogicalAncestorOfType(this ILogical? logical, bool includeSelf = false) where T : class
{
if (logical is null)
{
return null;
}
var parent = includeSelf ? logical : logical.LogicalParent;
while (parent != null)
{
if (parent is T result)
{
return result;
}
parent = parent.LogicalParent;
}
return null;
}
///
/// Enumerates the children of an in the logical tree.
///
/// The logical.
/// The logical children.
public static IEnumerable GetLogicalChildren(this ILogical logical)
{
return logical.LogicalChildren;
}
///
/// Enumerates the descendants of an in the logical tree.
///
/// The logical.
/// The logical's ancestors.
public static IEnumerable GetLogicalDescendants(this ILogical logical)
{
foreach (ILogical child in logical.LogicalChildren)
{
yield return child;
foreach (ILogical descendant in child.GetLogicalDescendants())
{
yield return descendant;
}
}
}
///
/// Enumerates an and its descendants in the logical tree.
///
/// The logical.
/// The logical and its ancestors.
public static IEnumerable GetSelfAndLogicalDescendants(this ILogical logical)
{
yield return logical;
foreach (var descendent in logical.GetLogicalDescendants())
{
yield return descendent;
}
}
///
/// Finds first descendant of given type.
///
/// Descendant type.
/// The logical.
/// If given logical should be included in search.
/// First descendant of given type.
public static T? FindLogicalDescendantOfType(this ILogical? logical, bool includeSelf = false) where T : class
{
if (logical is null)
{
return null;
}
if (includeSelf && logical is T result)
{
return result;
}
return FindDescendantOfTypeCore(logical);
}
///
/// Gets the logical parent of an .
///
/// The logical.
/// The parent, or null if the logical is unparented.
public static ILogical? GetLogicalParent(this ILogical logical)
{
return logical.LogicalParent;
}
///
/// Gets the logical parent of an .
///
/// The type of the logical parent.
/// The logical.
///
/// The parent, or null if the logical is unparented or its parent is not of type .
///
public static T? GetLogicalParent(this ILogical logical) where T : class
{
return logical.LogicalParent as T;
}
///
/// Enumerates the siblings of an in the logical tree.
///
/// The logical.
/// The logical siblings.
public static IEnumerable GetLogicalSiblings(this ILogical logical)
{
var parent = logical.LogicalParent;
if (parent != null)
{
foreach (ILogical sibling in parent.LogicalChildren)
{
yield return sibling;
}
}
}
///
/// Tests whether an is an ancestor of another logical.
///
/// The logical.
/// The potential descendant.
///
/// True if is an ancestor of ;
/// otherwise false.
///
public static bool IsLogicalAncestorOf(this ILogical? logical, ILogical? target)
{
var current = target?.LogicalParent;
while (current != null)
{
if (current == logical)
{
return true;
}
current = current.LogicalParent;
}
return false;
}
private static T? FindDescendantOfTypeCore(ILogical logical) where T : class
{
var logicalChildren = logical.LogicalChildren;
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
{
ILogical child = logicalChildren[i];
if (child is T result)
{
return result;
}
var childResult = FindDescendantOfTypeCore(child);
if (!(childResult is null))
{
return childResult;
}
}
return null;
}
}
}