Browse Source

Removed a number of interfaces.

`IAvaloniaObject`, `IControl`, `ILayoutable`, `IPanel`, `IStyledElement`, `IVisual`.
pull/9553/head
Steven Kirk 3 years ago
parent
commit
ec74057151
  1. 6
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  2. 2
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  3. 2
      src/Avalonia.Base/Animation/PageSlide.cs
  4. 2
      src/Avalonia.Base/AttachedProperty.cs
  5. 2
      src/Avalonia.Base/AvaloniaObject.cs
  6. 100
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  7. 22
      src/Avalonia.Base/AvaloniaProperty.cs
  8. 6
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
  9. 4
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
  10. 12
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  11. 2
      src/Avalonia.Base/AvaloniaProperty`1.cs
  12. 4
      src/Avalonia.Base/ClassBindingManager.cs
  13. 2
      src/Avalonia.Base/Controls/Classes.cs
  14. 2
      src/Avalonia.Base/Controls/ISetInheritanceParent.cs
  15. 3
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  16. 4
      src/Avalonia.Base/Data/BindingOperations.cs
  17. 4
      src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
  18. 2
      src/Avalonia.Base/Data/IBinding.cs
  19. 6
      src/Avalonia.Base/Data/IndexerBinding.cs
  20. 2
      src/Avalonia.Base/Data/InstancedBinding.cs
  21. 2
      src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
  22. 10
      src/Avalonia.Base/DirectProperty.cs
  23. 6
      src/Avalonia.Base/DirectPropertyBase.cs
  24. 79
      src/Avalonia.Base/IAvaloniaObject.cs
  25. 2
      src/Avalonia.Base/IDataContextProvider.cs
  26. 4
      src/Avalonia.Base/IDirectPropertyAccessor.cs
  27. 39
      src/Avalonia.Base/IStyledElement.cs
  28. 4
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  29. 5
      src/Avalonia.Base/Input/DragDropDevice.cs
  30. 2
      src/Avalonia.Base/Input/DragEventArgs.cs
  31. 17
      src/Avalonia.Base/Input/FocusManager.cs
  32. 4
      src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs
  33. 4
      src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs
  34. 6
      src/Avalonia.Base/Input/Gestures.cs
  35. 9
      src/Avalonia.Base/Input/IInputElement.cs
  36. 2
      src/Avalonia.Base/Input/IMainMenu.cs
  37. 17
      src/Avalonia.Base/Input/InputExtensions.cs
  38. 39
      src/Avalonia.Base/Input/KeyboardDevice.cs
  39. 2
      src/Avalonia.Base/Input/KeyboardNavigation.cs
  40. 6
      src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
  41. 14
      src/Avalonia.Base/Input/MouseDevice.cs
  42. 12
      src/Avalonia.Base/Input/Navigation/FocusExtensions.cs
  43. 18
      src/Avalonia.Base/Input/Navigation/TabNavigation.cs
  44. 6
      src/Avalonia.Base/Input/PenDevice.cs
  45. 20
      src/Avalonia.Base/Input/Pointer.cs
  46. 2
      src/Avalonia.Base/Input/PointerDeltaEventArgs.cs
  47. 18
      src/Avalonia.Base/Input/PointerEventArgs.cs
  48. 48
      src/Avalonia.Base/Input/PointerOverPreProcessor.cs
  49. 2
      src/Avalonia.Base/Input/PointerWheelEventArgs.cs
  50. 2
      src/Avalonia.Base/Input/TappedEventArgs.cs
  51. 2
      src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs
  52. 9
      src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
  53. 6
      src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs
  54. 6
      src/Avalonia.Base/Input/TouchDevice.cs
  55. 2
      src/Avalonia.Base/Interactivity/Interactive.cs
  56. 2
      src/Avalonia.Base/Layout/AttachedLayout.cs
  57. 14
      src/Avalonia.Base/Layout/ElementManager.cs
  58. 10
      src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs
  59. 6
      src/Avalonia.Base/Layout/IFlowLayoutAlgorithmDelegates.cs
  60. 8
      src/Avalonia.Base/Layout/ILayoutManager.cs
  61. 2
      src/Avalonia.Base/Layout/ILayoutRoot.cs
  62. 122
      src/Avalonia.Base/Layout/ILayoutable.cs
  63. 4
      src/Avalonia.Base/Layout/LayoutContextAdapter.cs
  64. 43
      src/Avalonia.Base/Layout/LayoutHelper.cs
  65. 38
      src/Avalonia.Base/Layout/LayoutManager.cs
  66. 35
      src/Avalonia.Base/Layout/Layoutable.cs
  67. 4
      src/Avalonia.Base/Layout/NonVirtualizingLayoutContext.cs
  68. 8
      src/Avalonia.Base/Layout/NonVirtualizingStackLayout.cs
  69. 12
      src/Avalonia.Base/Layout/StackLayout.cs
  70. 6
      src/Avalonia.Base/Layout/UniformGridLayout.cs
  71. 4
      src/Avalonia.Base/Layout/UniformGridLayoutState.cs
  72. 8
      src/Avalonia.Base/Layout/VirtualLayoutContextAdapter.cs
  73. 12
      src/Avalonia.Base/Layout/VirtualizingLayoutContext.cs
  74. 2
      src/Avalonia.Base/Layout/WrapLayout/WrapItem.cs
  75. 4
      src/Avalonia.Base/Media/IVisualBrush.cs
  76. 2
      src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs
  77. 4
      src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
  78. 10
      src/Avalonia.Base/Media/VisualBrush.cs
  79. 2
      src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
  80. 12
      src/Avalonia.Base/PropertyStore/UntypedValueUtils.cs
  81. 6
      src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs
  82. 6
      src/Avalonia.Base/Reactive/AvaloniaPropertyChangedObservable.cs
  83. 36
      src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs
  84. 14
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  85. 22
      src/Avalonia.Base/Rendering/DeferredRenderer.cs
  86. 14
      src/Avalonia.Base/Rendering/DirtyVisuals.cs
  87. 4
      src/Avalonia.Base/Rendering/ICustomSimpleHitTest.cs
  88. 2
      src/Avalonia.Base/Rendering/IRenderRoot.cs
  89. 8
      src/Avalonia.Base/Rendering/IRenderer.cs
  90. 38
      src/Avalonia.Base/Rendering/ImmediateRenderer.cs
  91. 4
      src/Avalonia.Base/Rendering/RenderLayer.cs
  92. 7
      src/Avalonia.Base/Rendering/RenderLayers.cs
  93. 4
      src/Avalonia.Base/Rendering/SceneGraph/ISceneBuilder.cs
  94. 5
      src/Avalonia.Base/Rendering/SceneGraph/IVisualNode.cs
  95. 40
      src/Avalonia.Base/Rendering/SceneGraph/Scene.cs
  96. 18
      src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs
  97. 5
      src/Avalonia.Base/Rendering/SceneGraph/SceneLayer.cs
  98. 22
      src/Avalonia.Base/Rendering/SceneGraph/SceneLayers.cs
  99. 6
      src/Avalonia.Base/Rendering/SceneGraph/VisualNode.cs
  100. 6
      src/Avalonia.Base/Rendering/ZIndexComparer.cs

6
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@ -293,10 +293,10 @@ namespace ControlCatalog.ViewModels
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
private static IVisual GetVisualParent(IVisual? from, IVisual? to)
private static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;
var p1 = (from ?? to)!.GetVisualParent();
var p2 = (to ?? from)!.GetVisualParent();
if (p1 != null && p2 != null && p1 != p2)
{

2
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -109,7 +109,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
? new CompositingRenderer(root, AndroidPlatform.Compositor)
: AndroidPlatform.Options.UseDeferredRendering
? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService<IRenderLoop>()) { RenderOnlyOnRenderThread = true }
: new ImmediateRenderer(root);
: new ImmediateRenderer((Visual)root);
public virtual void Hide()
{

2
src/Avalonia.Base/Animation/PageSlide.cs

@ -157,7 +157,7 @@ namespace Avalonia.Animation
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
protected static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;

2
src/Avalonia.Base/AttachedProperty.cs

@ -34,7 +34,7 @@ namespace Avalonia
/// </summary>
/// <typeparam name="TOwner">The owner type.</typeparam>
/// <returns>The property.</returns>
public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : IAvaloniaObject
public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : AvaloniaObject
{
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this);
return this;

2
src/Avalonia.Base/AvaloniaObject.cs

@ -16,7 +16,7 @@ namespace Avalonia
/// <remarks>
/// This class is analogous to DependencyObject in WPF.
/// </remarks>
public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
public class AvaloniaObject : IAvaloniaObjectDebug, INotifyPropertyChanged
{
private readonly ValueStore _values;
private AvaloniaObject? _inheritanceParent;

100
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@ -36,7 +36,7 @@ namespace Avalonia
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<object?> GetObservable(this IAvaloniaObject o, AvaloniaProperty property)
public static IObservable<object?> GetObservable(this AvaloniaObject o, AvaloniaProperty property)
{
return new AvaloniaPropertyObservable<object?>(
o ?? throw new ArgumentNullException(nameof(o)),
@ -56,7 +56,7 @@ namespace Avalonia
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<T> GetObservable<T>(this IAvaloniaObject o, AvaloniaProperty<T> property)
public static IObservable<T> GetObservable<T>(this AvaloniaObject o, AvaloniaProperty<T> property)
{
return new AvaloniaPropertyObservable<T>(
o ?? throw new ArgumentNullException(nameof(o)),
@ -76,7 +76,7 @@ namespace Avalonia
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<BindingValue<object?>> GetBindingObservable(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property)
{
return new AvaloniaPropertyBindingObservable<object?>(
@ -98,7 +98,7 @@ namespace Avalonia
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<BindingValue<T>> GetBindingObservable<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property)
{
return new AvaloniaPropertyBindingObservable<T>(
@ -115,11 +115,11 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <returns>
/// An observable which when subscribed pushes the property changed event args
/// each time a <see cref="IAvaloniaObject.PropertyChanged"/> event is raised
/// each time a <see cref="AvaloniaObject.PropertyChanged"/> event is raised
/// for the specified property.
/// </returns>
public static IObservable<AvaloniaPropertyChangedEventArgs> GetPropertyChangedObservable(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property)
{
return new AvaloniaPropertyChangedObservable(
@ -140,7 +140,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<object?> GetSubject(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -163,7 +163,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<T> GetSubject<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -185,7 +185,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<BindingValue<object?>> GetBindingSubject(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -214,7 +214,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<BindingValue<T>> GetBindingSubject<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -241,7 +241,7 @@ namespace Avalonia
/// A disposable which can be used to terminate the binding.
/// </returns>
public static IDisposable Bind<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property,
IObservable<BindingValue<T>> source,
BindingPriority priority = BindingPriority.LocalValue)
@ -250,17 +250,12 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
source = source ?? throw new ArgumentNullException(nameof(source));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
DirectPropertyBase<T> direct => ao.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
DirectPropertyBase<T> direct => target.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
/// <summary>
@ -274,22 +269,17 @@ namespace Avalonia
/// A disposable which can be used to terminate the binding.
/// </returns>
public static IDisposable Bind<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property,
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue)
{
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
DirectPropertyBase<T> direct => ao.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
DirectPropertyBase<T> direct => target.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
/// <summary>
@ -306,7 +296,7 @@ namespace Avalonia
/// </param>
/// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
public static IDisposable Bind(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty property,
IBinding binding,
object? anchor = null)
@ -340,23 +330,17 @@ namespace Avalonia
/// <param name="target">The object.</param>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
public static T GetValue<T>(this IAvaloniaObject target, AvaloniaProperty<T> property)
public static T GetValue<T>(this AvaloniaObject target, AvaloniaProperty<T> property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.GetValue(styled),
DirectPropertyBase<T> direct => ao.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.GetValue(styled),
DirectPropertyBase<T> direct => target.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
/// <summary>
@ -372,15 +356,13 @@ namespace Avalonia
/// For direct properties returns the current value of the property.
/// </remarks>
public static object? GetBaseValue(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property.RouteGetBaseValue(ao);
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
return property.RouteGetBaseValue(target);
}
/// <summary>
@ -396,24 +378,18 @@ namespace Avalonia
/// For direct properties returns the current value of the property.
/// </remarks>
public static Optional<T> GetBaseValue<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.GetBaseValue(styled),
DirectPropertyBase<T> direct => ao.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.GetBaseValue(styled),
DirectPropertyBase<T> direct => target.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
/// <summary>
@ -474,7 +450,7 @@ namespace Avalonia
}
public InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false)

22
src/Avalonia.Base/AvaloniaProperty.cs

@ -38,7 +38,7 @@ namespace Avalonia
Type valueType,
Type ownerType,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool>? notifying = null)
Action<AvaloniaObject, bool>? notifying = null)
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -145,7 +145,7 @@ namespace Avalonia
/// will be true before the property change notifications are sent and false afterwards. This
/// callback is intended to support Control.IsDataContextChanging.
/// </remarks>
public Action<IAvaloniaObject, bool>? Notifying { get; }
public Action<AvaloniaObject, bool>? Notifying { get; }
/// <summary>
/// Gets the integer ID that represents this property.
@ -238,9 +238,9 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null,
Action<IAvaloniaObject, bool>? notifying = null)
where TOwner : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null,
Action<AvaloniaObject, bool>? notifying = null)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -279,8 +279,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null)
where THost : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where THost : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -316,8 +316,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null)
where THost : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where THost : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -354,7 +354,7 @@ namespace Avalonia
TValue unsetValue = default!,
BindingMode defaultBindingMode = BindingMode.OneWay,
bool enableDataValidation = false)
where TOwner : IAvaloniaObject
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
_ = getter ?? throw new ArgumentNullException(nameof(getter));
@ -415,7 +415,7 @@ namespace Avalonia
/// <returns>
/// The property metadata.
/// </returns>
public AvaloniaPropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
public AvaloniaPropertyMetadata GetMetadata<T>() where T : AvaloniaObject
{
return GetMetadata(typeof(T));
}

6
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs

@ -9,7 +9,7 @@ namespace Avalonia
public abstract class AvaloniaPropertyChangedEventArgs : EventArgs
{
public AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
BindingPriority priority)
{
Sender = sender;
@ -18,7 +18,7 @@ namespace Avalonia
}
internal AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
BindingPriority priority,
bool isEffectiveValueChange)
{
@ -31,7 +31,7 @@ namespace Avalonia
/// Gets the <see cref="AvaloniaObject"/> that the property changed on.
/// </summary>
/// <value>The sender object.</value>
public IAvaloniaObject Sender { get; }
public AvaloniaObject Sender { get; }
/// <summary>
/// Gets the property that changed.

4
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs

@ -16,7 +16,7 @@ namespace Avalonia
/// <param name="newValue">The new value of the property.</param>
/// <param name="priority">The priority of the binding that produced the value.</param>
public AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
AvaloniaProperty<T> property,
Optional<T> oldValue,
BindingValue<T> newValue,
@ -26,7 +26,7 @@ namespace Avalonia
}
internal AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
AvaloniaProperty<T> property,
Optional<T> oldValue,
BindingValue<T> newValue,

12
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -189,7 +189,7 @@ namespace Avalonia
/// </summary>
/// <param name="o">The object.</param>
/// <returns>A collection of <see cref="AvaloniaProperty"/> definitions.</returns>
public IReadOnlyList<AvaloniaProperty> GetRegistered(IAvaloniaObject o)
public IReadOnlyList<AvaloniaProperty> GetRegistered(AvaloniaObject o)
{
_ = o ?? throw new ArgumentNullException(nameof(o));
@ -205,7 +205,7 @@ namespace Avalonia
/// The registered.
/// </returns>
public DirectPropertyBase<T> GetRegisteredDirect<T>(
IAvaloniaObject o,
AvaloniaObject o,
DirectPropertyBase<T> property)
{
return FindRegisteredDirect(o, property) ??
@ -260,7 +260,7 @@ namespace Avalonia
/// <exception cref="InvalidOperationException">
/// The property name contains a '.'.
/// </exception>
public AvaloniaProperty? FindRegistered(IAvaloniaObject o, string name)
public AvaloniaProperty? FindRegistered(AvaloniaObject o, string name)
{
_ = o ?? throw new ArgumentNullException(nameof(o));
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -277,7 +277,7 @@ namespace Avalonia
/// The registered property or null if no matching property found.
/// </returns>
public DirectPropertyBase<T>? FindRegisteredDirect<T>(
IAvaloniaObject o,
AvaloniaObject o,
DirectPropertyBase<T> property)
{
if (property.Owner == o.GetType())
@ -362,7 +362,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <remarks>
/// You won't usually want to call this method directly, instead use the
/// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue}, Action{IAvaloniaObject, bool})"/>
/// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue}, Action{AvaloniaObject, bool})"/>
/// method.
/// </remarks>
public void Register(Type type, AvaloniaProperty property)
@ -413,7 +413,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <remarks>
/// You won't usually want to call this method directly, instead use the
/// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue})"/>
/// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue})"/>
/// method.
/// </remarks>
public void RegisterAttached(Type type, AvaloniaProperty property)

2
src/Avalonia.Base/AvaloniaProperty`1.cs

@ -24,7 +24,7 @@ namespace Avalonia
string name,
Type ownerType,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool>? notifying = null)
Action<AvaloniaObject, bool>? notifying = null)
: base(name, typeof(TValue), ownerType, metadata, notifying)
{
_changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();

4
src/Avalonia.Base/ClassBindingManager.cs

@ -9,7 +9,7 @@ namespace Avalonia
private static readonly Dictionary<string, AvaloniaProperty> s_RegisteredProperties =
new Dictionary<string, AvaloniaProperty>();
public static IDisposable Bind(IStyledElement target, string className, IBinding source, object anchor)
public static IDisposable Bind(StyledElement target, string className, IBinding source, object anchor)
{
if (!s_RegisteredProperties.TryGetValue(className, out var prop))
s_RegisteredProperties[className] = prop = RegisterClassProxyProperty(className);
@ -21,7 +21,7 @@ namespace Avalonia
var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);
prop.Changed.Subscribe(args =>
{
var classes = ((IStyledElement)args.Sender).Classes;
var classes = ((StyledElement)args.Sender).Classes;
classes.Set(className, args.NewValue.GetValueOrDefault());
});

2
src/Avalonia.Base/Controls/Classes.cs

@ -6,7 +6,7 @@ using Avalonia.Utilities;
namespace Avalonia.Controls
{
/// <summary>
/// Holds a collection of style classes for an <see cref="IStyledElement"/>.
/// Holds a collection of style classes for an <see cref="StyledElement"/>.
/// </summary>
/// <remarks>
/// Similar to CSS, each control may have any number of styling classes applied.

2
src/Avalonia.Base/Controls/ISetInheritanceParent.cs

@ -17,6 +17,6 @@ namespace Avalonia.Controls
/// Sets the control's inheritance parent.
/// </summary>
/// <param name="parent">The parent.</param>
void SetParent(IAvaloniaObject? parent);
void SetParent(AvaloniaObject? parent);
}
}

3
src/Avalonia.Base/Controls/ResourceNodeExtensions.cs

@ -2,6 +2,7 @@
using Avalonia.Data.Converters;
using Avalonia.LogicalTree;
using Avalonia.Reactive;
using Avalonia.Styling;
#nullable enable
@ -49,7 +50,7 @@ namespace Avalonia.Controls
return true;
}
current = (current as IStyledElement)?.StylingParent as IResourceNode;
current = (current as IStyleHost)?.StylingParent as IResourceNode;
}
value = null;

4
src/Avalonia.Base/Data/BindingOperations.cs

@ -9,7 +9,7 @@ namespace Avalonia.Data
public static readonly object DoNothing = new DoNothingType();
/// <summary>
/// Applies an <see cref="InstancedBinding"/> a property on an <see cref="IAvaloniaObject"/>.
/// Applies an <see cref="InstancedBinding"/> a property on an <see cref="AvaloniaObject"/>.
/// </summary>
/// <param name="target">The target object.</param>
/// <param name="property">The property to bind.</param>
@ -22,7 +22,7 @@ namespace Avalonia.Data
/// </param>
/// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
public static IDisposable Apply(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty property,
InstancedBinding binding,
object? anchor)

4
src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs

@ -24,7 +24,7 @@ namespace Avalonia.Data.Core
{
try
{
if (Target.TryGetTarget(out var target) && target is IAvaloniaObject obj)
if (Target.TryGetTarget(out var target) && target is AvaloniaObject obj)
{
obj.SetValue(_property, value, priority);
return true;
@ -39,7 +39,7 @@ namespace Avalonia.Data.Core
protected override void StartListeningCore(WeakReference<object?> reference)
{
if (reference.TryGetTarget(out var target) && target is IAvaloniaObject obj)
if (reference.TryGetTarget(out var target) && target is AvaloniaObject obj)
{
_subscription = new AvaloniaPropertyObservable<object?>(obj, _property).Subscribe(ValueChanged);
}

2
src/Avalonia.Base/Data/IBinding.cs

@ -24,7 +24,7 @@ namespace Avalonia.Data
/// A <see cref="InstancedBinding"/> or null if the binding could not be resolved.
/// </returns>
InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false);

6
src/Avalonia.Base/Data/IndexerBinding.cs

@ -3,7 +3,7 @@
public class IndexerBinding : IBinding
{
public IndexerBinding(
IAvaloniaObject source,
AvaloniaObject source,
AvaloniaProperty property,
BindingMode mode)
{
@ -12,12 +12,12 @@
Mode = mode;
}
private IAvaloniaObject Source { get; }
private AvaloniaObject Source { get; }
public AvaloniaProperty Property { get; }
private BindingMode Mode { get; }
public InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false)

2
src/Avalonia.Base/Data/InstancedBinding.cs

@ -9,7 +9,7 @@ namespace Avalonia.Data
/// <remarks>
/// Whereas an <see cref="IBinding"/> holds a description of a binding such as "Bind to the X
/// property on a control's DataContext"; this class represents a binding that has been
/// *instanced* by calling <see cref="IBinding.Initiate(IAvaloniaObject, AvaloniaProperty, object, bool)"/>
/// *instanced* by calling <see cref="IBinding.Initiate(AvaloniaObject, AvaloniaProperty, object, bool)"/>
/// on a target object.
/// </remarks>
public class InstancedBinding

2
src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs

@ -8,7 +8,7 @@ namespace Avalonia.Diagnostics
public interface IAvaloniaObjectDebug
{
/// <summary>
/// Gets the subscriber list for the <see cref="IAvaloniaObject.PropertyChanged"/>
/// Gets the subscriber list for the <see cref="AvaloniaObject.PropertyChanged"/>
/// event.
/// </summary>
/// <returns>

10
src/Avalonia.Base/DirectProperty.cs

@ -15,7 +15,7 @@ namespace Avalonia
/// allows the avalonia property system to read and write the current value.
/// </remarks>
public class DirectProperty<TOwner, TValue> : DirectPropertyBase<TValue>, IDirectPropertyAccessor
where TOwner : IAvaloniaObject
where TOwner : AvaloniaObject
{
/// <summary>
/// Initializes a new instance of the <see cref="DirectProperty{TOwner, TValue}"/> class.
@ -151,13 +151,13 @@ namespace Avalonia
}
/// <inheritdoc/>
internal override TValue InvokeGetter(IAvaloniaObject instance)
internal override TValue InvokeGetter(AvaloniaObject instance)
{
return Getter((TOwner)instance);
}
/// <inheritdoc/>
internal override void InvokeSetter(IAvaloniaObject instance, BindingValue<TValue> value)
internal override void InvokeSetter(AvaloniaObject instance, BindingValue<TValue> value)
{
if (Setter == null)
{
@ -171,13 +171,13 @@ namespace Avalonia
}
/// <inheritdoc/>
object? IDirectPropertyAccessor.GetValue(IAvaloniaObject instance)
object? IDirectPropertyAccessor.GetValue(AvaloniaObject instance)
{
return Getter((TOwner)instance);
}
/// <inheritdoc/>
void IDirectPropertyAccessor.SetValue(IAvaloniaObject instance, object? value)
void IDirectPropertyAccessor.SetValue(AvaloniaObject instance, object? value)
{
if (Setter == null)
{

6
src/Avalonia.Base/DirectPropertyBase.cs

@ -54,14 +54,14 @@ namespace Avalonia
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>The property value.</returns>
internal abstract TValue InvokeGetter(IAvaloniaObject instance);
internal abstract TValue InvokeGetter(AvaloniaObject instance);
/// <summary>
/// Sets the value of the property on the instance.
/// </summary>
/// <param name="instance">The instance.</param>
/// <param name="value">The value.</param>
internal abstract void InvokeSetter(IAvaloniaObject instance, BindingValue<TValue> value);
internal abstract void InvokeSetter(AvaloniaObject instance, BindingValue<TValue> value);
/// <summary>
/// Gets the unset value for the property on the specified type.
@ -91,7 +91,7 @@ namespace Avalonia
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="metadata">The metadata.</param>
public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : IAvaloniaObject
public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : AvaloniaObject
{
base.OverrideMetadata(typeof(T), metadata);
}

79
src/Avalonia.Base/IAvaloniaObject.cs

@ -1,79 +0,0 @@
using System;
using Avalonia.Data;
using Avalonia.Metadata;
namespace Avalonia
{
/// <summary>
/// Interface for getting/setting <see cref="AvaloniaProperty"/> values on an object.
/// </summary>
[NotClientImplementable]
public interface IAvaloniaObject
{
/// <summary>
/// Raised when a <see cref="AvaloniaProperty"/> value changes on this object.
/// </summary>
event EventHandler<AvaloniaPropertyChangedEventArgs>? PropertyChanged;
/// <summary>
/// Clears an <see cref="AvaloniaProperty"/>'s local value.
/// </summary>
/// <param name="property">The property.</param>
void ClearValue(AvaloniaProperty property);
/// <summary>
/// Gets a <see cref="AvaloniaProperty"/> value.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
object? GetValue(AvaloniaProperty property);
/// <summary>
/// Checks whether a <see cref="AvaloniaProperty"/> is animating.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>True if the property is animating, otherwise false.</returns>
bool IsAnimating(AvaloniaProperty property);
/// <summary>
/// Checks whether a <see cref="AvaloniaProperty"/> is set on this object.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>True if the property is set, otherwise false.</returns>
bool IsSet(AvaloniaProperty property);
/// <summary>
/// Sets a <see cref="AvaloniaProperty"/> value.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <param name="priority">The priority of the value.</param>
/// <returns>
/// An <see cref="IDisposable"/> if setting the property can be undone, otherwise null.
/// </returns>
IDisposable? SetValue(
AvaloniaProperty property,
object? value,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Binds a <see cref="AvaloniaProperty"/> to an observable.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="source">The observable.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
IDisposable Bind(
AvaloniaProperty property,
IObservable<object?> source,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Coerces the specified <see cref="AvaloniaProperty"/>.
/// </summary>
/// <param name="property">The property.</param>
void CoerceValue(AvaloniaProperty property);
}
}

2
src/Avalonia.Base/IDataContextProvider.cs

@ -6,7 +6,7 @@ namespace Avalonia
/// Defines an element with a data context that can be used for binding.
/// </summary>
[NotClientImplementable]
public interface IDataContextProvider : IAvaloniaObject
public interface IDataContextProvider
{
/// <summary>
/// Gets or sets the element's data context.

4
src/Avalonia.Base/IDirectPropertyAccessor.cs

@ -24,13 +24,13 @@ namespace Avalonia
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>The property value.</returns>
object? GetValue(IAvaloniaObject instance);
object? GetValue(AvaloniaObject instance);
/// <summary>
/// Sets the value of the property on the instance.
/// </summary>
/// <param name="instance">The instance.</param>
/// <param name="value">The value.</param>
void SetValue(IAvaloniaObject instance, object? value);
void SetValue(AvaloniaObject instance, object? value);
}
}

39
src/Avalonia.Base/IStyledElement.cs

@ -1,39 +0,0 @@
using System;
using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Styling;
namespace Avalonia
{
[NotClientImplementable]
public interface IStyledElement :
IStyleable,
IStyleHost,
ILogical,
IResourceHost,
IDataContextProvider,
ISupportInitialize
{
/// <summary>
/// Occurs when the control has finished initialization.
/// </summary>
event EventHandler? Initialized;
/// <summary>
/// Gets a value that indicates whether the element has finished initialization.
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Gets or sets the control's styling classes.
/// </summary>
new Classes Classes { get; set; }
/// <summary>
/// Gets the control's logical parent.
/// </summary>
IStyledElement? Parent { get; }
}
}

4
src/Avalonia.Base/Input/AccessKeyHandler.cs

@ -182,13 +182,13 @@ namespace Avalonia.Input
// find all controls who have registered that access key.
var text = e.Key.ToString().ToUpper();
var matches = _registered
.Where(x => x.Item1 == text && x.Item2.IsEffectivelyVisible)
.Where(x => x.Item1 == text && ((Visual)x.Item2).IsEffectivelyVisible)
.Select(x => x.Item2);
// If the menu is open, only match controls in the menu's visual tree.
if (menuIsOpen)
{
matches = matches.Where(x => x is not null && MainMenu!.IsVisualAncestorOf(x));
matches = matches.Where(x => x is not null && ((Visual)MainMenu!).IsVisualAncestorOf((Visual)x));
}
var match = matches.FirstOrDefault();

5
src/Avalonia.Base/Input/DragDropDevice.cs

@ -13,7 +13,8 @@ namespace Avalonia.Input
private Interactive? GetTarget(IInputRoot root, Point local)
{
var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
var hit = root.InputHitTest(local) as Visual;
var target = hit?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
if (target != null && DragDrop.GetAllowDrop(target))
return target;
return null;
@ -24,7 +25,7 @@ namespace Avalonia.Input
if (target == null)
return DragDropEffects.None;
var p = inputRoot.TranslatePoint(point, target);
var p = ((Visual)inputRoot).TranslatePoint(point, target);
if (!p.HasValue)
return DragDropEffects.None;

2
src/Avalonia.Base/Input/DragEventArgs.cs

@ -15,7 +15,7 @@ namespace Avalonia.Input
public KeyModifiers KeyModifiers { get; private set; }
public Point GetPosition(IVisual relativeTo)
public Point GetPosition(Visual relativeTo)
{
var point = new Point(0, 0);

17
src/Avalonia.Base/Input/FocusManager.cs

@ -185,7 +185,7 @@ namespace Avalonia.Input
/// </summary>
/// <param name="e">The element.</param>
/// <returns>True if the element can be focused.</returns>
private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && e.IsVisible;
private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && IsVisible(e);
/// <summary>
/// Gets the focus scope ancestors of the specified control, traversing popups.
@ -198,14 +198,15 @@ namespace Avalonia.Input
while (c != null)
{
var scope = c as IFocusScope;
if (scope != null && c.VisualRoot?.IsVisible == true)
if (c is IFocusScope scope &&
c is Visual v &&
v.VisualRoot is Visual root &&
root.IsVisible)
{
yield return scope;
}
c = c.GetVisualParent<IInputElement>() ??
c = (c as Visual)?.GetVisualParent<IInputElement>() ??
((c as IHostedVisualTreeRoot)?.Host as IInputElement);
}
}
@ -221,11 +222,11 @@ namespace Avalonia.Input
return;
var ev = (PointerPressedEventArgs)e;
var visual = (IVisual)sender;
var visual = (Visual)sender;
if (sender == e.Source && ev.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
IVisual? element = ev.Pointer?.Captured ?? e.Source as IInputElement;
Visual? element = ev.Pointer?.Captured as Visual ?? e.Source as Visual;
while (element != null)
{
@ -240,5 +241,7 @@ namespace Avalonia.Input
}
}
}
private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true;
}
}

4
src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs

@ -35,8 +35,8 @@ namespace Avalonia.Input.GestureRecognizers
if (_inputElement is ILogical logicalParent && recognizer is ISetLogicalParent logical)
{
logical.SetParent(logicalParent);
if (recognizer is IStyleable styleableRecognizer
&& _inputElement is IStyleable styleableParent)
if (recognizer is StyledElement styleableRecognizer
&& _inputElement is StyledElement styleableParent)
styleableRecognizer.Bind(StyledElement.TemplatedParentProperty,
styleableParent.GetObservable(StyledElement.TemplatedParentProperty));
}

4
src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs

@ -72,7 +72,7 @@ namespace Avalonia.Input.GestureRecognizers
EndGesture();
_tracking = e.Pointer;
_gestureId = ScrollGestureEventArgs.GetNextFreeId();
_trackedRootPoint = e.GetPosition(_target);
_trackedRootPoint = e.GetPosition((Visual?)_target);
}
}
@ -86,7 +86,7 @@ namespace Avalonia.Input.GestureRecognizers
{
if (e.Pointer == _tracking)
{
var rootPoint = e.GetPosition(_target);
var rootPoint = e.GetPosition((Visual?)_target);
if (!_scrolling)
{
if (CanHorizontallyScroll && Math.Abs(_trackedRootPoint.X - rootPoint.X) > ScrollStartDistance)

6
src/Avalonia.Base/Input/Gestures.cs

@ -92,13 +92,13 @@ namespace Avalonia.Input
if (ev.Route == RoutingStrategies.Bubble)
{
var e = (PointerPressedEventArgs)ev;
var visual = (IVisual)ev.Source;
var visual = (Visual)ev.Source;
if (e.ClickCount % 2 == 1)
{
s_isDoubleTapped = false;
s_lastPress.SetTarget(ev.Source);
s_lastPressPoint = e.GetPosition((IVisual)ev.Source);
s_lastPressPoint = e.GetPosition((Visual)ev.Source);
}
else if (e.ClickCount % 2 == 0 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
@ -121,7 +121,7 @@ namespace Avalonia.Input
target == e.Source &&
e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right)
{
var point = e.GetCurrentPoint((IVisual)target);
var point = e.GetCurrentPoint((Visual)target);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(s_lastPressPoint, new Size())

9
src/Avalonia.Base/Input/IInputElement.cs

@ -12,7 +12,7 @@ namespace Avalonia.Input
/// Defines input-related functionality for a control.
/// </summary>
[NotClientImplementable]
public interface IInputElement : IInteractive, IVisual
public interface IInputElement : IInteractive
{
/// <summary>
/// Occurs when the control receives focus.
@ -93,7 +93,12 @@ namespace Avalonia.Input
/// <see cref="IsEnabled"/> value of this control and its parent controls.
/// </remarks>
bool IsEffectivelyEnabled { get; }
/// <summary>
/// Gets a value indicating whether this control and all its parents are visible.
/// </summary>
bool IsEffectivelyVisible { get; }
/// <summary>
/// Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements.
/// </summary>

2
src/Avalonia.Base/Input/IMainMenu.cs

@ -9,7 +9,7 @@ namespace Avalonia.Input
/// Defines the interface for a window's main menu.
/// </summary>
[NotClientImplementable]
public interface IMainMenu : IVisual
public interface IMainMenu
{
/// <summary>
/// Gets a value indicating whether the menu is open.

17
src/Avalonia.Base/Input/InputExtensions.cs

@ -12,7 +12,7 @@ namespace Avalonia.Input
/// </summary>
public static class InputExtensions
{
private static readonly Func<IVisual, bool> s_hitTestDelegate = IsHitTestVisible;
private static readonly Func<Visual, bool> s_hitTestDelegate = IsHitTestVisible;
/// <summary>
/// Returns the active input elements at a point on an <see cref="IInputElement"/>.
@ -26,7 +26,8 @@ namespace Avalonia.Input
{
element = element ?? throw new ArgumentNullException(nameof(element));
return element.GetVisualsAt(p, s_hitTestDelegate).Cast<IInputElement>();
return (element as Visual)?.GetVisualsAt(p, s_hitTestDelegate).Cast<IInputElement>() ??
Enumerable.Empty<IInputElement>();
}
/// <summary>
@ -39,7 +40,7 @@ namespace Avalonia.Input
{
element = element ?? throw new ArgumentNullException(nameof(element));
return element.GetVisualAt(p, s_hitTestDelegate) as IInputElement;
return (element as Visual)?.GetVisualAt(p, s_hitTestDelegate) as IInputElement;
}
/// <summary>
@ -55,22 +56,22 @@ namespace Avalonia.Input
public static IInputElement? InputHitTest(
this IInputElement element,
Point p,
Func<IVisual, bool> filter)
Func<Visual, bool> filter)
{
element = element ?? throw new ArgumentNullException(nameof(element));
filter = filter ?? throw new ArgumentNullException(nameof(filter));
return element.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement;
return (element as Visual)?.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement;
}
private static bool IsHitTestVisible(IVisual visual)
private static bool IsHitTestVisible(Visual visual)
{
var element = visual as IInputElement;
return element != null &&
element.IsVisible &&
visual.IsVisible &&
element.IsHitTestVisible &&
element.IsEffectivelyEnabled &&
element.IsAttachedToVisualTree;
visual.IsAttachedToVisualTree;
}
}
}

39
src/Avalonia.Base/Input/KeyboardDevice.cs

@ -3,7 +3,6 @@ using System.Runtime.CompilerServices;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
namespace Avalonia.Input
{
@ -37,18 +36,21 @@ namespace Avalonia.Input
ie.IsKeyboardFocusWithin = false;
}
el = (IInputElement?)el.VisualParent;
el = (IInputElement?)(el as Visual)?.VisualParent;
}
}
private void ClearFocusWithin(IInputElement element, bool clearRoot)
{
foreach (var visual in element.VisualChildren)
if (element is Visual v)
{
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
foreach (var visual in v.VisualChildren)
{
ClearFocusWithin(el, true);
break;
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
{
ClearFocusWithin(el, true);
break;
}
}
}
@ -81,7 +83,7 @@ namespace Avalonia.Input
break;
}
el = el.VisualParent as IInputElement;
el = (el as Visual)?.VisualParent as IInputElement;
}
el = oldElement;
@ -100,18 +102,21 @@ namespace Avalonia.Input
ie.IsKeyboardFocusWithin = true;
}
el = el.VisualParent as IInputElement;
el = (el as Visual)?.VisualParent as IInputElement;
}
}
private void ClearChildrenFocusWithin(IInputElement element, bool clearRoot)
{
foreach (var visual in element.VisualChildren)
if (element is Visual v)
{
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
foreach (var visual in v.VisualChildren)
{
ClearChildrenFocusWithin(el, true);
break;
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
{
ClearChildrenFocusWithin(el, true);
break;
}
}
}
@ -131,8 +136,8 @@ namespace Avalonia.Input
var interactive = FocusedElement as IInteractive;
if (FocusedElement != null &&
(!FocusedElement.IsAttachedToVisualTree ||
_focusedRoot != element?.VisualRoot as IInputRoot) &&
(!((Visual)FocusedElement).IsAttachedToVisualTree ||
_focusedRoot != ((Visual?)element)?.VisualRoot as IInputRoot) &&
_focusedRoot != null)
{
ClearChildrenFocusWithin(_focusedRoot, true);
@ -140,7 +145,7 @@ namespace Avalonia.Input
SetIsFocusWithin(FocusedElement, element);
_focusedElement = element;
_focusedRoot = _focusedElement?.VisualRoot as IInputRoot;
_focusedRoot = ((Visual?)_focusedElement)?.VisualRoot as IInputRoot;
interactive?.RaiseEvent(new RoutedEventArgs
{
@ -191,8 +196,8 @@ namespace Avalonia.Input
KeyModifiers = keyInput.Modifiers.ToKeyModifiers(),
Source = element,
};
IVisual? currentHandler = element;
var currentHandler = element as Visual;
while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown)
{
var bindings = (currentHandler as IInputElement)?.KeyBindings;

2
src/Avalonia.Base/Input/KeyboardNavigation.cs

@ -68,7 +68,7 @@ namespace Avalonia.Input
/// <param name="value">The tab index.</param>
public static void SetTabIndex(IInputElement element, int value)
{
((IAvaloniaObject)element).SetValue(TabIndexProperty, value);
((AvaloniaObject)element).SetValue(TabIndexProperty, value);
}
/// <summary>

6
src/Avalonia.Base/Input/KeyboardNavigationHandler.cs

@ -50,7 +50,7 @@ namespace Avalonia.Input
element = element ?? throw new ArgumentNullException(nameof(element));
// If there's a custom keyboard navigation handler as an ancestor, use that.
var custom = element.FindAncestorOfType<ICustomKeyboardNavigation>(true);
var custom = (element as Visual)?.FindAncestorOfType<ICustomKeyboardNavigation>(true);
if (custom is object && HandlePreCustomNavigation(custom, element, direction, out var ce))
return ce;
@ -156,9 +156,9 @@ namespace Avalonia.Input
NavigationDirection direction,
[NotNullWhen(true)] out IInputElement? result)
{
if (newElement is object)
if (newElement is Visual v)
{
var customHandler = newElement.FindAncestorOfType<ICustomKeyboardNavigation>(true);
var customHandler = v.FindAncestorOfType<ICustomKeyboardNavigation>(true);
if (customHandler is object)
{

14
src/Avalonia.Base/Input/MouseDevice.cs

@ -141,7 +141,7 @@ namespace Avalonia.Input
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, _pointer, root, p, timestamp, properties, inputModifiers, _clickCount);
var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
source.RaiseEvent(e);
return e.Handled;
}
@ -161,7 +161,7 @@ namespace Avalonia.Input
if (source is object)
{
var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, root,
var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, (Visual)root,
p, timestamp, properties, inputModifiers, intermediatePoints);
source.RaiseEvent(e);
@ -181,7 +181,7 @@ namespace Avalonia.Input
if (source is not null)
{
var e = new PointerReleasedEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers,
var e = new PointerReleasedEventArgs(source, _pointer, (Visual)root, p, timestamp, props, inputModifiers,
_lastMouseDownButton);
source?.RaiseEvent(e);
@ -204,7 +204,7 @@ namespace Avalonia.Input
if (source is not null)
{
var e = new PointerWheelEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers, delta);
var e = new PointerWheelEventArgs(source, _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
source?.RaiseEvent(e);
return e.Handled;
@ -224,7 +224,7 @@ namespace Avalonia.Input
if (source != null)
{
var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureMagnifyEvent, source,
_pointer, root, p, timestamp, props, inputModifiers, delta);
_pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
source?.RaiseEvent(e);
return e.Handled;
@ -244,7 +244,7 @@ namespace Avalonia.Input
if (source != null)
{
var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureRotateEvent, source,
_pointer, root, p, timestamp, props, inputModifiers, delta);
_pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
source?.RaiseEvent(e);
return e.Handled;
@ -264,7 +264,7 @@ namespace Avalonia.Input
if (source != null)
{
var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureSwipeEvent, source,
_pointer, root, p, timestamp, props, inputModifiers, delta);
_pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
source?.RaiseEvent(e);
return e.Handled;

12
src/Avalonia.Base/Input/Navigation/FocusExtensions.cs

@ -10,13 +10,21 @@ namespace Avalonia.Input.Navigation
/// </summary>
/// <param name="e">The element.</param>
/// <returns>True if the element can be focused.</returns>
public static bool CanFocus(this IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && e.IsVisible;
public static bool CanFocus(this IInputElement e)
{
var visible = (e as Visual)?.IsVisible ?? true;
return e.Focusable && e.IsEffectivelyEnabled && visible;
}
/// <summary>
/// Checks if descendants of the specified element can be focused.
/// </summary>
/// <param name="e">The element.</param>
/// <returns>True if descendants of the element can be focused.</returns>
public static bool CanFocusDescendants(this IInputElement e) => e.IsEffectivelyEnabled && e.IsVisible;
public static bool CanFocusDescendants(this IInputElement e)
{
var visible = (e as Visual)?.IsVisible ?? true;
return e.IsEffectivelyEnabled && visible;
}
}
}

18
src/Avalonia.Base/Input/Navigation/TabNavigation.cs

@ -212,9 +212,10 @@ namespace Avalonia.Input.Navigation
if (!IsFocusScope(e))
{
// Verify if focusedElement is a visual descendant of e
if (focusedElement is IVisual visualFocusedElement &&
if (focusedElement is Visual visualFocusedElement &&
e is Visual v &&
visualFocusedElement != e &&
e.IsVisualAncestorOf(visualFocusedElement))
v.IsVisualAncestorOf(visualFocusedElement))
{
return focusedElement;
}
@ -236,7 +237,7 @@ namespace Avalonia.Input.Navigation
if (uiElement is null || IsVisibleAndEnabled(uiElement))
{
if (e is IVisual elementAsVisual)
if (e is Visual elementAsVisual)
{
var children = elementAsVisual.VisualChildren;
var count = children.Count;
@ -272,7 +273,7 @@ namespace Avalonia.Input.Navigation
if (uiElement == null || IsVisibleAndEnabled(uiElement))
{
var elementAsVisual = e as IVisual;
var elementAsVisual = e as Visual;
if (elementAsVisual != null)
{
@ -385,7 +386,7 @@ namespace Avalonia.Input.Navigation
private static IInputElement? GetNextSibling(IInputElement e)
{
if (GetParent(e) is IVisual parentAsVisual && e is IVisual elementAsVisual)
if (GetParent(e) is Visual parentAsVisual && e is Visual elementAsVisual)
{
var children = parentAsVisual.VisualChildren;
var count = children.Count;
@ -589,7 +590,7 @@ namespace Avalonia.Input.Navigation
private static IInputElement? GetPreviousSibling(IInputElement e)
{
if (GetParent(e) is IVisual parentAsVisual && e is IVisual elementAsVisual)
if (GetParent(e) is Visual parentAsVisual && e is Visual elementAsVisual)
{
var children = parentAsVisual.VisualChildren;
var count = children.Count;
@ -646,7 +647,7 @@ namespace Avalonia.Input.Navigation
private static IInputElement? GetParent(IInputElement e)
{
// For Visual - go up the visual parent chain until we find Visual.
if (e is IVisual v)
if (e is Visual v)
return v.FindAncestorOfType<IInputElement>();
// This will need to be implemented when we have non-visual input elements.
@ -669,6 +670,7 @@ namespace Avalonia.Input.Navigation
}
private static bool IsTabStopOrGroup(IInputElement e) => IsTabStop(e) || IsGroup(e);
private static bool IsVisibleAndEnabled(IInputElement e) => e.IsVisible && e.IsEnabled;
private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true;
private static bool IsVisibleAndEnabled(IInputElement e) => IsVisible(e) && e.IsEnabled;
}
}

6
src/Avalonia.Base/Input/PenDevice.cs

@ -91,7 +91,7 @@ namespace Avalonia.Input
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, pointer, root, p, timestamp, properties, inputModifiers, _clickCount);
var e = new PointerPressedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
source.RaiseEvent(e);
return e.Handled;
}
@ -108,7 +108,7 @@ namespace Avalonia.Input
if (source is not null)
{
var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, pointer, root,
var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, pointer, (Visual)root,
p, timestamp, properties, inputModifiers, intermediatePoints);
source.RaiseEvent(e);
@ -126,7 +126,7 @@ namespace Avalonia.Input
if (source is not null)
{
var e = new PointerReleasedEventArgs(source, pointer, root, p, timestamp, properties, inputModifiers,
var e = new PointerReleasedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers,
_lastMouseDownButton);
source?.RaiseEvent(e);

20
src/Avalonia.Base/Input/Pointer.cs

@ -21,10 +21,10 @@ namespace Avalonia.Input
IInputElement? FindCommonParent(IInputElement? control1, IInputElement? control2)
{
if (control1 == null || control2 == null)
if (control1 is not Visual c1 || control2 is not Visual c2)
return null;
var seen = new HashSet<IInputElement>(control1.GetSelfAndVisualAncestors().OfType<IInputElement>());
return control2.GetSelfAndVisualAncestors().OfType<IInputElement>().FirstOrDefault(seen.Contains);
var seen = new HashSet<IInputElement>(c1.GetSelfAndVisualAncestors().OfType<IInputElement>());
return c2.GetSelfAndVisualAncestors().OfType<IInputElement>().FirstOrDefault(seen.Contains);
}
protected virtual void PlatformCapture(IInputElement? element)
@ -34,15 +34,15 @@ namespace Avalonia.Input
public void Capture(IInputElement? control)
{
if (Captured != null)
Captured.DetachedFromVisualTree -= OnCaptureDetached;
if (Captured is Visual v1)
v1.DetachedFromVisualTree -= OnCaptureDetached;
var oldCapture = Captured;
Captured = control;
PlatformCapture(control);
if (oldCapture != null)
if (oldCapture is Visual v2)
{
var commonParent = FindCommonParent(control, oldCapture);
foreach (var notifyTarget in oldCapture.GetSelfAndVisualAncestors().OfType<IInputElement>())
foreach (var notifyTarget in v2.GetSelfAndVisualAncestors().OfType<IInputElement>())
{
if (notifyTarget == commonParent)
break;
@ -50,11 +50,11 @@ namespace Avalonia.Input
}
}
if (Captured != null)
Captured.DetachedFromVisualTree += OnCaptureDetached;
if (Captured is Visual v3)
v3.DetachedFromVisualTree += OnCaptureDetached;
}
IInputElement? GetNextCapture(IVisual parent)
IInputElement? GetNextCapture(Visual parent)
{
return parent as IInputElement ?? parent.FindAncestorOfType<IInputElement>();
}

2
src/Avalonia.Base/Input/PointerDeltaEventArgs.cs

@ -8,7 +8,7 @@ namespace Avalonia.Input
public Vector Delta { get; set; }
internal PointerDeltaEventArgs(RoutedEvent routedEvent, IInteractive? source,
IPointer pointer, IVisual rootVisual, Point rootVisualPosition, ulong timestamp,
IPointer pointer, Visual rootVisual, Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, KeyModifiers modifiers, Vector delta)
: base(routedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers)

18
src/Avalonia.Base/Input/PointerEventArgs.cs

@ -8,7 +8,7 @@ namespace Avalonia.Input
{
public class PointerEventArgs : RoutedEventArgs
{
private readonly IVisual? _rootVisual;
private readonly Visual? _rootVisual;
private readonly Point _rootVisualPosition;
private readonly PointerPointProperties _properties;
private readonly Lazy<IReadOnlyList<RawPointerPoint>?>? _previousPoints;
@ -16,7 +16,7 @@ namespace Avalonia.Input
internal PointerEventArgs(RoutedEvent routedEvent,
IInteractive? source,
IPointer pointer,
IVisual? rootVisual, Point rootVisualPosition,
Visual? rootVisual, Point rootVisualPosition,
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers)
@ -34,7 +34,7 @@ namespace Avalonia.Input
internal PointerEventArgs(RoutedEvent routedEvent,
IInteractive? source,
IPointer pointer,
IVisual? rootVisual, Point rootVisualPosition,
Visual? rootVisual, Point rootVisualPosition,
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
@ -59,7 +59,7 @@ namespace Avalonia.Input
/// </summary>
public KeyModifiers KeyModifiers { get; }
private Point GetPosition(Point pt, IVisual? relativeTo)
private Point GetPosition(Point pt, Visual? relativeTo)
{
if (_rootVisual == null)
return default;
@ -74,14 +74,14 @@ namespace Avalonia.Input
/// </summary>
/// <param name="relativeTo">The control.</param>
/// <returns>The pointer position in the control's coordinates.</returns>
public Point GetPosition(IVisual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
public Point GetPosition(Visual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
/// <summary>
/// Returns the PointerPoint associated with the current event
/// </summary>
/// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns></returns>
public PointerPoint GetCurrentPoint(IVisual? relativeTo)
public PointerPoint GetCurrentPoint(Visual? relativeTo)
=> new PointerPoint(Pointer, GetPosition(relativeTo), _properties);
/// <summary>
@ -89,7 +89,7 @@ namespace Avalonia.Input
/// </summary>
/// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns></returns>
public IReadOnlyList<PointerPoint> GetIntermediatePoints(IVisual? relativeTo)
public IReadOnlyList<PointerPoint> GetIntermediatePoints(Visual? relativeTo)
{
var previousPoints = _previousPoints?.Value;
if (previousPoints == null || previousPoints.Count == 0)
@ -127,7 +127,7 @@ namespace Avalonia.Input
internal PointerPressedEventArgs(
IInteractive source,
IPointer pointer,
IVisual rootVisual, Point rootVisualPosition,
Visual rootVisual, Point rootVisualPosition,
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
@ -145,7 +145,7 @@ namespace Avalonia.Input
{
internal PointerReleasedEventArgs(
IInteractive source, IPointer pointer,
IVisual rootVisual, Point rootVisualPosition, ulong timestamp,
Visual rootVisual, Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, KeyModifiers modifiers,
MouseButton initialPressMouseButton)
: base(InputElement.PointerReleasedEvent, source, pointer, rootVisual, rootVisualPosition,

48
src/Avalonia.Base/Input/PointerOverPreProcessor.cs

@ -44,7 +44,7 @@ namespace Avalonia.Input
&& _lastPointer is (var lastPointer, var lastPosition))
{
_lastPointer = null;
ClearPointerOver(lastPointer, args.Root, 0, args.Root.PointToClient(lastPosition),
ClearPointerOver(lastPointer, args.Root, 0, PointToClient(args.Root, lastPosition),
new PointerPointProperties(args.InputModifiers, args.Type.ToUpdateKind()),
args.InputModifiers.ToKeyModifiers());
}
@ -64,14 +64,14 @@ namespace Avalonia.Input
{
if (_lastPointer is (var pointer, var position))
{
var clientPoint = _inputRoot.PointToClient(position);
var clientPoint = PointToClient(_inputRoot, position);
if (dirtyRect.Contains(clientPoint))
{
var element = pointer.Captured ?? _inputRoot.InputHitTest(clientPoint);
SetPointerOver(pointer, _inputRoot, element, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None);
}
else if (!_inputRoot.Bounds.Contains(clientPoint))
else if (!((Visual)_inputRoot).Bounds.Contains(clientPoint))
{
ClearPointerOver(pointer, _inputRoot, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None);
}
@ -82,7 +82,7 @@ namespace Avalonia.Input
{
if (_lastPointer is (var pointer, var position))
{
var clientPoint = _inputRoot.PointToClient(position);
var clientPoint = PointToClient(_inputRoot, position);
ClearPointerOver(pointer, _inputRoot, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None);
}
_lastPointer = null;
@ -101,10 +101,10 @@ namespace Avalonia.Input
// Do not pass rootVisual, when we have unknown position,
// so GetPosition won't return invalid values.
var e = new PointerEventArgs(InputElement.PointerExitedEvent, element, pointer,
position.HasValue ? root : null, position.HasValue ? position.Value : default,
position.HasValue ? root as Visual : null, position.HasValue ? position.Value : default,
timestamp, properties, inputModifiers);
if (element != null && !element.IsAttachedToVisualTree)
if (element is Visual v && !v.IsAttachedToVisualTree)
{
// element has been removed from visual tree so do top down cleanup
if (root.IsPointerOver)
@ -117,7 +117,7 @@ namespace Avalonia.Input
e.Source = element;
e.Handled = false;
element.RaiseEvent(e);
element = (IInputElement?)element.VisualParent;
element = GetVisualParent(element);
}
root.PointerOverElement = null;
@ -127,14 +127,18 @@ namespace Avalonia.Input
private void ClearChildrenPointerOver(PointerEventArgs e, IInputElement element, bool clearRoot)
{
foreach (IInputElement el in element.VisualChildren)
if (element is Visual v)
{
if (el.IsPointerOver)
foreach (IInputElement el in v.VisualChildren)
{
ClearChildrenPointerOver(e, el, true);
break;
if (el.IsPointerOver)
{
ClearChildrenPointerOver(e, el, true);
break;
}
}
}
if (clearRoot)
{
e.Source = element;
@ -160,7 +164,7 @@ namespace Avalonia.Input
}
}
_lastPointer = (pointer, root.PointToScreen(position));
_lastPointer = (pointer, ((Visual)root).PointToScreen(position));
}
private void SetPointerOverToElement(IPointer pointer, IInputRoot root, IInputElement element,
@ -177,14 +181,14 @@ namespace Avalonia.Input
branch = el;
break;
}
el = (IInputElement?)el.VisualParent;
el = GetVisualParent(el);
}
el = root.PointerOverElement;
var e = new PointerEventArgs(InputElement.PointerExitedEvent, el, pointer, root, position,
var e = new PointerEventArgs(InputElement.PointerExitedEvent, el, pointer, (Visual)root, position,
timestamp, properties, inputModifiers);
if (el != null && branch != null && !el.IsAttachedToVisualTree)
if (el is Visual v && branch != null && !v.IsAttachedToVisualTree)
{
ClearChildrenPointerOver(e, branch, false);
}
@ -194,7 +198,7 @@ namespace Avalonia.Input
e.Source = el;
e.Handled = false;
el.RaiseEvent(e);
el = (IInputElement?)el.VisualParent;
el = GetVisualParent(el);
}
el = root.PointerOverElement = element;
@ -206,8 +210,18 @@ namespace Avalonia.Input
e.Source = el;
e.Handled = false;
el.RaiseEvent(e);
el = (IInputElement?)el.VisualParent;
el = GetVisualParent(el);
}
}
private static IInputElement? GetVisualParent(IInputElement e)
{
return (e as Visual)?.VisualParent as IInputElement;
}
private static Point PointToClient(IInputRoot root, PixelPoint p)
{
return ((Visual)root).PointToClient(p);
}
}
}

2
src/Avalonia.Base/Input/PointerWheelEventArgs.cs

@ -7,7 +7,7 @@ namespace Avalonia.Input
{
public Vector Delta { get; set; }
internal PointerWheelEventArgs(IInteractive source, IPointer pointer, IVisual rootVisual,
internal PointerWheelEventArgs(IInteractive source, IPointer pointer, Visual rootVisual,
Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, KeyModifiers modifiers, Vector delta)
: base(InputElement.PointerWheelChangedEvent, source, pointer, rootVisual, rootVisualPosition,

2
src/Avalonia.Base/Input/TappedEventArgs.cs

@ -17,6 +17,6 @@ namespace Avalonia.Input
public KeyModifiers KeyModifiers => lastPointerEventArgs.KeyModifiers;
public ulong Timestamp => lastPointerEventArgs.Timestamp;
public Point GetPosition(IVisual? relativeTo) => lastPointerEventArgs.GetPosition(relativeTo);
public Point GetPosition(Visual? relativeTo) => lastPointerEventArgs.GetPosition(relativeTo);
}
}

2
src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs

@ -16,7 +16,7 @@ namespace Avalonia.Input.TextInput
/// <summary>
/// The visual that's showing the text
/// </summary>
IVisual TextViewVisual { get; }
Visual TextViewVisual { get; }
/// <summary>
/// Should be fired when text-hosting visual is changed
/// </summary>

9
src/Avalonia.Base/Input/TextInput/InputMethodManager.cs

@ -73,10 +73,13 @@ namespace Avalonia.Input.TextInput
private void UpdateCursorRect()
{
if (_im == null || _client == null || _focusedElement?.VisualRoot == null)
if (_im == null ||
_client == null ||
_focusedElement is not Visual v ||
v.VisualRoot is not Visual root)
return;
var transform = _focusedElement.TransformToVisual(_focusedElement.VisualRoot);
var transform = v.TransformToVisual(root);
if (transform == null)
_im.SetCursorRect(default);
else
@ -95,7 +98,7 @@ namespace Avalonia.Input.TextInput
return;
_focusedElement = element;
var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
var inputMethod = ((element as Visual)?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
if (_im != inputMethod)
{

6
src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs

@ -7,7 +7,7 @@ namespace Avalonia.Input.TextInput
{
class TransformTrackingHelper : IDisposable
{
private IVisual? _visual;
private Visual? _visual;
private bool _queuedForUpdate;
private readonly EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChangedHandler;
private readonly List<Visual> _propertyChangedSubscriptions = new List<Visual>();
@ -17,7 +17,7 @@ namespace Avalonia.Input.TextInput
_propertyChangedHandler = PropertyChangedHandler;
}
public void SetVisual(IVisual? visual)
public void SetVisual(Visual? visual)
{
Dispose();
_visual = visual;
@ -72,7 +72,7 @@ namespace Avalonia.Input.TextInput
{
Matrix? matrix = null;
if (_visual != null && _visual.VisualRoot != null)
matrix = _visual.TransformToVisual(_visual.VisualRoot);
matrix = _visual.TransformToVisual((Visual)_visual.VisualRoot);
if (Matrix != matrix)
{
Matrix = matrix;

6
src/Avalonia.Base/Input/TouchDevice.cs

@ -75,7 +75,7 @@ namespace Avalonia.Input
}
target.RaiseEvent(new PointerPressedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp,
(Visual)args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind),
keyModifier, _clickCount));
}
@ -86,7 +86,7 @@ namespace Avalonia.Input
using (pointer)
{
target.RaiseEvent(new PointerReleasedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp,
(Visual)args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, false), updateKind),
keyModifier, MouseButton.Left));
}
@ -101,7 +101,7 @@ namespace Avalonia.Input
if (args.Type == RawPointerEventType.TouchUpdate)
{
target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root,
target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, (Visual)args.Root,
args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind),
keyModifier, args.IntermediatePoints));

2
src/Avalonia.Base/Interactivity/Interactive.cs

@ -17,7 +17,7 @@ namespace Avalonia.Interactivity
/// <summary>
/// Gets the interactive parent of the object for bubbling and tunneling events.
/// </summary>
IInteractive? IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive;
IInteractive? IInteractive.InteractiveParent => this.VisualParent as IInteractive;
/// <summary>
/// Adds a handler for the specified routed event.

2
src/Avalonia.Base/Layout/AttachedLayout.cs

@ -43,7 +43,7 @@ namespace Avalonia.Layout
/// <summary>
/// Initializes any per-container state the layout requires when it is attached to an
/// <see cref="ILayoutable"/> container.
/// <see cref="Layoutable"/> container.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host

14
src/Avalonia.Base/Layout/ElementManager.cs

@ -13,7 +13,7 @@ namespace Avalonia.Layout
{
internal class ElementManager
{
private readonly List<ILayoutable?> _realizedElements = new List<ILayoutable?>();
private readonly List<Layoutable?> _realizedElements = new List<Layoutable?>();
private readonly List<Rect> _realizedElementLayoutBounds = new List<Rect>();
private int _firstRealizedDataIndex;
private VirtualizingLayoutContext? _context;
@ -69,9 +69,9 @@ namespace Avalonia.Layout
return IsVirtualizingContext ? _realizedElements.Count : _context!.ItemCount;
}
public ILayoutable GetAt(int realizedIndex)
public Layoutable GetAt(int realizedIndex)
{
ILayoutable? element;
Layoutable? element;
if (IsVirtualizingContext)
{
@ -99,7 +99,7 @@ namespace Avalonia.Layout
return element;
}
public void Add(ILayoutable element, int dataIndex)
public void Add(Layoutable element, int dataIndex)
{
if (_realizedElements.Count == 0)
{
@ -110,7 +110,7 @@ namespace Avalonia.Layout
_realizedElementLayoutBounds.Add(default);
}
public void Insert(int realizedIndex, int dataIndex, ILayoutable? element)
public void Insert(int realizedIndex, int dataIndex, Layoutable? element)
{
if (realizedIndex == 0)
{
@ -207,7 +207,7 @@ namespace Avalonia.Layout
public bool IsIndexValidInData(int currentIndex) => (uint)currentIndex < _context!.ItemCount;
public ILayoutable? GetRealizedElement(int dataIndex)
public Layoutable? GetRealizedElement(int dataIndex)
{
return IsVirtualizingContext ?
GetAt(GetRealizedRangeIndexFromDataIndex(dataIndex)) :
@ -330,7 +330,7 @@ namespace Avalonia.Layout
}
}
public int GetElementDataIndex(ILayoutable suggestedAnchor)
public int GetElementDataIndex(Layoutable suggestedAnchor)
{
var it = _realizedElements.IndexOf(suggestedAnchor);
return it != -1 ? GetDataIndexFromRealizedRangeIndex(it) : -1;

10
src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs

@ -144,7 +144,7 @@ namespace Avalonia.Layout
}
public Size MeasureElement(
ILayoutable element,
Layoutable element,
int index,
Size availableSize,
VirtualizingLayoutContext context)
@ -512,9 +512,9 @@ namespace Avalonia.Layout
private Rect EstimateExtent(Size availableSize, string? layoutId)
{
ILayoutable? firstRealizedElement = null;
Layoutable? firstRealizedElement = null;
Rect firstBounds = new Rect();
ILayoutable? lastRealizedElement = null;
Layoutable? lastRealizedElement = null;
Rect lastBounds = new Rect();
int firstDataIndex = -1;
int lastDataIndex = -1;
@ -727,7 +727,7 @@ namespace Avalonia.Layout
}
}
public ILayoutable? GetElementIfRealized(int dataIndex)
public Layoutable? GetElementIfRealized(int dataIndex)
{
if (_elementManager.IsDataIndexRealized(dataIndex))
{
@ -737,7 +737,7 @@ namespace Avalonia.Layout
return null;
}
public bool TryAddElement0(ILayoutable element)
public bool TryAddElement0(Layoutable element)
{
if (_elementManager.GetRealizedElementCount() == 0)
{

6
src/Avalonia.Base/Layout/IFlowLayoutAlgorithmDelegates.cs

@ -21,14 +21,14 @@ namespace Avalonia.Layout
Rect Algorithm_GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable? firstRealized,
Layoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable? lastRealized,
Layoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds);
void Algorithm_OnElementMeasured(
ILayoutable element,
Layoutable element,
int index,
Size availableSize,
Size measureSize,

8
src/Avalonia.Base/Layout/ILayoutManager.cs

@ -18,13 +18,13 @@ namespace Avalonia.Layout
/// Notifies the layout manager that a control requires a measure.
/// </summary>
/// <param name="control">The control.</param>
void InvalidateMeasure(ILayoutable control);
void InvalidateMeasure(Layoutable control);
/// <summary>
/// Notifies the layout manager that a control requires an arrange.
/// </summary>
/// <param name="control">The control.</param>
void InvalidateArrange(ILayoutable control);
void InvalidateArrange(Layoutable control);
/// <summary>
/// Executes a layout pass.
@ -48,12 +48,12 @@ namespace Avalonia.Layout
/// Registers a control as wanting to receive effective viewport notifications.
/// </summary>
/// <param name="control">The control.</param>
void RegisterEffectiveViewportListener(ILayoutable control);
void RegisterEffectiveViewportListener(Layoutable control);
/// <summary>
/// Registers a control as no longer wanting to receive effective viewport notifications.
/// </summary>
/// <param name="control">The control.</param>
void UnregisterEffectiveViewportListener(ILayoutable control);
void UnregisterEffectiveViewportListener(Layoutable control);
}
}

2
src/Avalonia.Base/Layout/ILayoutRoot.cs

@ -6,7 +6,7 @@ namespace Avalonia.Layout
/// Defines the root of a layoutable tree.
/// </summary>
[NotClientImplementable]
public interface ILayoutRoot : ILayoutable
public interface ILayoutRoot
{
/// <summary>
/// The size available to lay out the controls.

122
src/Avalonia.Base/Layout/ILayoutable.cs

@ -1,122 +0,0 @@
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Layout
{
/// <summary>
/// Defines layout-related functionality for a control.
/// </summary>
[NotClientImplementable]
public interface ILayoutable : IVisual
{
/// <summary>
/// Gets the size that this element computed during the measure pass of the layout process.
/// </summary>
Size DesiredSize { get; }
/// <summary>
/// Gets the width of the element.
/// </summary>
double Width { get; }
/// <summary>
/// Gets the height of the element.
/// </summary>
double Height { get; }
/// <summary>
/// Gets the minimum width of the element.
/// </summary>
double MinWidth { get; }
/// <summary>
/// Gets the maximum width of the element.
/// </summary>
double MaxWidth { get; }
/// <summary>
/// Gets the minimum height of the element.
/// </summary>
double MinHeight { get; }
/// <summary>
/// Gets the maximum height of the element.
/// </summary>
double MaxHeight { get; }
/// <summary>
/// Gets the margin around the element.
/// </summary>
Thickness Margin { get; }
/// <summary>
/// Gets the element's preferred horizontal alignment in its parent.
/// </summary>
HorizontalAlignment HorizontalAlignment { get; }
/// <summary>
/// Gets the element's preferred vertical alignment in its parent.
/// </summary>
VerticalAlignment VerticalAlignment { get; }
/// <summary>
/// Gets a value indicating whether the control's layout measure is valid.
/// </summary>
bool IsMeasureValid { get; }
/// <summary>
/// Gets a value indicating whether the control's layouts arrange is valid.
/// </summary>
bool IsArrangeValid { get; }
/// <summary>
/// Gets the available size passed in the previous layout pass, if any.
/// </summary>
Size? PreviousMeasure { get; }
/// <summary>
/// Gets the layout rect passed in the previous layout pass, if any.
/// </summary>
Rect? PreviousArrange { get; }
/// <summary>
/// Creates the visual children of the control, if necessary
/// </summary>
void ApplyTemplate();
/// <summary>
/// Carries out a measure of the control.
/// </summary>
/// <param name="availableSize">The available size for the control.</param>
void Measure(Size availableSize);
/// <summary>
/// Arranges the control and its children.
/// </summary>
/// <param name="rect">The control's new bounds.</param>
void Arrange(Rect rect);
/// <summary>
/// Invalidates the measurement of the control and queues a new layout pass.
/// </summary>
void InvalidateMeasure();
/// <summary>
/// Invalidates the arrangement of the control and queues a new layout pass.
/// </summary>
void InvalidateArrange();
/// <summary>
/// Called when a child control's desired size changes.
/// </summary>
/// <param name="control">The child control.</param>
void ChildDesiredSizeChanged(ILayoutable control);
/// <summary>
/// Used by the <see cref="LayoutManager"/> to notify the control that its effective
/// viewport is changed.
/// </summary>
/// <param name="e">The viewport information.</param>
void EffectiveViewportChanged(EffectiveViewportChangedEventArgs e);
}
}

4
src/Avalonia.Base/Layout/LayoutContextAdapter.cs

@ -38,8 +38,8 @@ namespace Avalonia.Layout
protected override int ItemCountCore() => _nonVirtualizingContext.Children.Count;
protected override object GetItemAtCore(int index) => _nonVirtualizingContext.Children[index];
protected override ILayoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options) =>
protected override Layoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options) =>
_nonVirtualizingContext.Children[index];
protected override void RecycleElementCore(ILayoutable element) { }
protected override void RecycleElementCore(Layoutable element) { }
}
}

43
src/Avalonia.Base/Layout/LayoutHelper.cs

@ -16,15 +16,15 @@ namespace Avalonia.Layout
public static double LayoutEpsilon { get; } = 0.00000153;
/// <summary>
/// Calculates a control's size based on its <see cref="ILayoutable.Width"/>,
/// <see cref="ILayoutable.Height"/>, <see cref="ILayoutable.MinWidth"/>,
/// <see cref="ILayoutable.MaxWidth"/>, <see cref="ILayoutable.MinHeight"/> and
/// <see cref="ILayoutable.MaxHeight"/>.
/// Calculates a control's size based on its <see cref="Layoutable.Width"/>,
/// <see cref="Layoutable.Height"/>, <see cref="Layoutable.MinWidth"/>,
/// <see cref="Layoutable.MaxWidth"/>, <see cref="Layoutable.MinHeight"/> and
/// <see cref="Layoutable.MaxHeight"/>.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="constraints">The space available for the control.</param>
/// <returns>The control's size.</returns>
public static Size ApplyLayoutConstraints(ILayoutable control, Size constraints)
public static Size ApplyLayoutConstraints(Layoutable control, Size constraints)
{
var minmax = new MinMax(control);
@ -33,7 +33,7 @@ namespace Avalonia.Layout
MathUtilities.Clamp(constraints.Height, minmax.MinHeight, minmax.MaxHeight));
}
public static Size MeasureChild(ILayoutable? control, Size availableSize, Thickness padding,
public static Size MeasureChild(Layoutable? control, Size availableSize, Thickness padding,
Thickness borderThickness)
{
if (IsParentLayoutRounded(control, out double scale))
@ -51,7 +51,7 @@ namespace Avalonia.Layout
return new Size().Inflate(padding + borderThickness);
}
public static Size MeasureChild(ILayoutable? control, Size availableSize, Thickness padding)
public static Size MeasureChild(Layoutable? control, Size availableSize, Thickness padding)
{
if (IsParentLayoutRounded(control, out double scale))
{
@ -67,7 +67,7 @@ namespace Avalonia.Layout
return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
}
public static Size ArrangeChild(ILayoutable? child, Size availableSize, Thickness padding, Thickness borderThickness)
public static Size ArrangeChild(Layoutable? child, Size availableSize, Thickness padding, Thickness borderThickness)
{
if (IsParentLayoutRounded(child, out double scale))
{
@ -78,7 +78,7 @@ namespace Avalonia.Layout
return ArrangeChildInternal(child, availableSize, padding + borderThickness);
}
public static Size ArrangeChild(ILayoutable? child, Size availableSize, Thickness padding)
public static Size ArrangeChild(Layoutable? child, Size availableSize, Thickness padding)
{
if(IsParentLayoutRounded(child, out double scale))
padding = RoundLayoutThickness(padding, scale, scale);
@ -86,18 +86,18 @@ namespace Avalonia.Layout
return ArrangeChildInternal(child, availableSize, padding);
}
private static Size ArrangeChildInternal(ILayoutable? child, Size availableSize, Thickness padding)
private static Size ArrangeChildInternal(Layoutable? child, Size availableSize, Thickness padding)
{
child?.Arrange(new Rect(availableSize).Deflate(padding));
return availableSize;
}
private static bool IsParentLayoutRounded(ILayoutable? child, out double scale)
private static bool IsParentLayoutRounded(Layoutable? child, out double scale)
{
var layoutableParent = (ILayoutable?)child?.GetVisualParent();
var layoutableParent = (child as Visual)?.GetVisualParent() as Layoutable;
if (layoutableParent == null || !((Layoutable)layoutableParent).UseLayoutRounding)
if (layoutableParent == null || !layoutableParent.UseLayoutRounding)
{
scale = 1.0;
return false;
@ -110,11 +110,11 @@ namespace Avalonia.Layout
/// <summary>
/// Invalidates measure for given control and all visual children recursively.
/// </summary>
public static void InvalidateSelfAndChildrenMeasure(ILayoutable control)
public static void InvalidateSelfAndChildrenMeasure(Layoutable control)
{
void InnerInvalidateMeasure(IVisual target)
void InnerInvalidateMeasure(Visual target)
{
if (target is ILayoutable targetLayoutable)
if (target is Layoutable targetLayoutable)
{
targetLayoutable.InvalidateMeasure();
}
@ -124,13 +124,14 @@ namespace Avalonia.Layout
for (int i = 0; i < visualChildrenCount; i++)
{
IVisual child = visualChildren[i];
Visual child = visualChildren[i];
InnerInvalidateMeasure(child);
}
}
InnerInvalidateMeasure(control);
if (control is Visual v)
InnerInvalidateMeasure(v);
}
/// <summary>
@ -138,9 +139,9 @@ namespace Avalonia.Layout
/// </summary>
/// <param name="control">The control.</param>
/// <exception cref="Exception">Thrown when control has no root or returned layout scaling is invalid.</exception>
public static double GetLayoutScale(ILayoutable control)
public static double GetLayoutScale(Layoutable control)
{
var visualRoot = control.VisualRoot;
var visualRoot = (control as Visual)?.VisualRoot;
var result = (visualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
@ -289,7 +290,7 @@ namespace Avalonia.Layout
/// </summary>
private readonly struct MinMax
{
public MinMax(ILayoutable e)
public MinMax(Layoutable e)
{
MaxHeight = e.MaxHeight;
MinHeight = e.MinHeight;

38
src/Avalonia.Base/Layout/LayoutManager.cs

@ -16,9 +16,9 @@ namespace Avalonia.Layout
public class LayoutManager : ILayoutManager, IDisposable
{
private const int MaxPasses = 3;
private readonly ILayoutRoot _owner;
private readonly LayoutQueue<ILayoutable> _toMeasure = new LayoutQueue<ILayoutable>(v => !v.IsMeasureValid);
private readonly LayoutQueue<ILayoutable> _toArrange = new LayoutQueue<ILayoutable>(v => !v.IsArrangeValid);
private readonly Layoutable _owner;
private readonly LayoutQueue<Layoutable> _toMeasure = new LayoutQueue<Layoutable>(v => !v.IsMeasureValid);
private readonly LayoutQueue<Layoutable> _toArrange = new LayoutQueue<Layoutable>(v => !v.IsArrangeValid);
private readonly Action _executeLayoutPass;
private List<EffectiveViewportChangedListener>? _effectiveViewportChangedListeners;
private bool _disposed;
@ -27,14 +27,14 @@ namespace Avalonia.Layout
public LayoutManager(ILayoutRoot owner)
{
_owner = owner ?? throw new ArgumentNullException(nameof(owner));
_owner = owner as Layoutable ?? throw new ArgumentNullException(nameof(owner));
_executeLayoutPass = ExecuteQueuedLayoutPass;
}
public virtual event EventHandler? LayoutUpdated;
/// <inheritdoc/>
public virtual void InvalidateMeasure(ILayoutable control)
public virtual void InvalidateMeasure(Layoutable control)
{
control = control ?? throw new ArgumentNullException(nameof(control));
Dispatcher.UIThread.VerifyAccess();
@ -65,7 +65,7 @@ namespace Avalonia.Layout
}
/// <inheritdoc/>
public virtual void InvalidateArrange(ILayoutable control)
public virtual void InvalidateArrange(Layoutable control)
{
control = control ?? throw new ArgumentNullException(nameof(control));
Dispatcher.UIThread.VerifyAccess();
@ -203,7 +203,7 @@ namespace Avalonia.Layout
_toArrange.Dispose();
}
void ILayoutManager.RegisterEffectiveViewportListener(ILayoutable control)
void ILayoutManager.RegisterEffectiveViewportListener(Layoutable control)
{
_effectiveViewportChangedListeners ??= new List<EffectiveViewportChangedListener>();
_effectiveViewportChangedListeners.Add(new EffectiveViewportChangedListener(
@ -211,7 +211,7 @@ namespace Avalonia.Layout
CalculateEffectiveViewport(control)));
}
void ILayoutManager.UnregisterEffectiveViewportListener(ILayoutable control)
void ILayoutManager.UnregisterEffectiveViewportListener(Layoutable control)
{
if (_effectiveViewportChangedListeners is object)
{
@ -265,13 +265,13 @@ namespace Avalonia.Layout
}
}
private void Measure(ILayoutable control)
private void Measure(Layoutable control)
{
// Controls closest to the visual root need to be arranged first. We don't try to store
// ordered invalidation lists, instead we traverse the tree upwards, measuring the
// controls closest to the root first. This has been shown by benchmarks to be the
// fastest and most memory-efficient algorithm.
if (control.VisualParent is ILayoutable parent)
if (control.VisualParent is Layoutable parent)
{
Measure(parent);
}
@ -283,7 +283,7 @@ namespace Avalonia.Layout
{
if (control is ILayoutRoot root)
{
root.Measure(Size.Infinity);
control.Measure(Size.Infinity);
}
else if (control.PreviousMeasure.HasValue)
{
@ -292,9 +292,9 @@ namespace Avalonia.Layout
}
}
private void Arrange(ILayoutable control)
private void Arrange(Layoutable control)
{
if (control.VisualParent is ILayoutable parent)
if (control.VisualParent is Layoutable parent)
{
Arrange(parent);
}
@ -304,7 +304,7 @@ namespace Avalonia.Layout
if (control is IEmbeddedLayoutRoot embeddedRoot)
control.Arrange(new Rect(embeddedRoot.AllocatedSize));
else if (control is ILayoutRoot root)
control.Arrange(new Rect(root.DesiredSize));
control.Arrange(new Rect(control.DesiredSize));
else if (control.PreviousArrange != null)
{
// Has been observed that PreviousArrange sometimes is null, probably a bug somewhere else.
@ -350,7 +350,7 @@ namespace Avalonia.Layout
if (viewport != l.Viewport)
{
l.Listener.EffectiveViewportChanged(new EffectiveViewportChangedEventArgs(viewport));
l.Listener.RaiseEffectiveViewportChanged(new EffectiveViewportChangedEventArgs(viewport));
l.Viewport = viewport;
}
}
@ -364,14 +364,14 @@ namespace Avalonia.Layout
return startCount != _toMeasure.Count + _toArrange.Count;
}
private Rect CalculateEffectiveViewport(IVisual control)
private Rect CalculateEffectiveViewport(Visual control)
{
var viewport = new Rect(0, 0, double.PositiveInfinity, double.PositiveInfinity);
CalculateEffectiveViewport(control, control, ref viewport);
return viewport;
}
private void CalculateEffectiveViewport(IVisual target, IVisual control, ref Rect viewport)
private void CalculateEffectiveViewport(Visual target, Visual control, ref Rect viewport)
{
// Recurse until the top level control.
if (control.VisualParent is object)
@ -405,13 +405,13 @@ namespace Avalonia.Layout
private class EffectiveViewportChangedListener
{
public EffectiveViewportChangedListener(ILayoutable listener, Rect viewport)
public EffectiveViewportChangedListener(Layoutable listener, Rect viewport)
{
Listener = listener;
Viewport = viewport;
}
public ILayoutable Listener { get; }
public Layoutable Listener { get; }
public Rect Viewport { get; set; }
}
}

35
src/Avalonia.Base/Layout/Layoutable.cs

@ -62,7 +62,7 @@ namespace Avalonia.Layout
/// <summary>
/// Implements layout-related functionality for a control.
/// </summary>
public class Layoutable : Visual, ILayoutable
public class Layoutable : Visual
{
/// <summary>
/// Defines the <see cref="DesiredSize"/> property.
@ -323,15 +323,12 @@ namespace Avalonia.Layout
set { SetValue(UseLayoutRoundingProperty, value); }
}
/// <summary>
/// Gets the available size passed in the previous layout pass, if any.
/// </summary>
Size? ILayoutable.PreviousMeasure => _previousMeasure;
internal Size? PreviousMeasure => _previousMeasure;
/// <summary>
/// Gets the layout rect passed in the previous layout pass, if any.
/// </summary>
Rect? ILayoutable.PreviousArrange => _previousArrange;
internal Rect? PreviousArrange => _previousArrange;
/// <summary>
/// Creates the visual children of the control, if necessary
@ -380,7 +377,7 @@ namespace Avalonia.Layout
if (DesiredSize != previousDesiredSize)
{
this.GetVisualParent<ILayoutable>()?.ChildDesiredSizeChanged(this);
this.GetVisualParent<Layoutable>()?.ChildDesiredSizeChanged(this);
}
}
}
@ -423,7 +420,7 @@ namespace Avalonia.Layout
IsMeasureValid = false;
IsArrangeValid = false;
if (((ILayoutable)this).IsAttachedToVisualTree)
if (IsAttachedToVisualTree)
{
(VisualRoot as ILayoutRoot)?.LayoutManager.InvalidateMeasure(this);
InvalidateVisual();
@ -448,7 +445,7 @@ namespace Avalonia.Layout
}
/// <inheritdoc/>
void ILayoutable.ChildDesiredSizeChanged(ILayoutable control)
internal void ChildDesiredSizeChanged(Layoutable control)
{
if (!_measuring)
{
@ -456,11 +453,11 @@ namespace Avalonia.Layout
}
}
void ILayoutable.EffectiveViewportChanged(EffectiveViewportChangedEventArgs e)
internal void RaiseEffectiveViewportChanged(EffectiveViewportChangedEventArgs e)
{
_effectiveViewportChanged?.Invoke(this, e);
}
/// <summary>
/// Marks a property as affecting the control's measurement.
/// </summary>
@ -471,7 +468,7 @@ namespace Avalonia.Layout
/// property will cause <see cref="InvalidateMeasure"/> to be called on the element.
/// </remarks>
protected static void AffectsMeasure<T>(params AvaloniaProperty[] properties)
where T : class, ILayoutable
where T : Layoutable
{
void Invalidate(AvaloniaPropertyChangedEventArgs e)
{
@ -494,7 +491,7 @@ namespace Avalonia.Layout
/// property will cause <see cref="InvalidateArrange"/> to be called on the element.
/// </remarks>
protected static void AffectsArrange<T>(params AvaloniaProperty[] properties)
where T : class, ILayoutable
where T : Layoutable
{
void Invalidate(AvaloniaPropertyChangedEventArgs e)
{
@ -596,9 +593,9 @@ namespace Avalonia.Layout
for (var i = 0; i < visualCount; i++)
{
IVisual visual = visualChildren[i];
Visual visual = visualChildren[i];
if (visual is ILayoutable layoutable)
if (visual is Layoutable layoutable)
{
layoutable.Measure(availableSize);
width = Math.Max(width, layoutable.DesiredSize.Width);
@ -709,9 +706,9 @@ namespace Avalonia.Layout
for (var i = 0; i < visualCount; i++)
{
IVisual visual = visualChildren[i];
Visual visual = visualChildren[i];
if (visual is ILayoutable layoutable)
if (visual is Layoutable layoutable)
{
layoutable.Arrange(arrangeRect);
}
@ -778,7 +775,7 @@ namespace Avalonia.Layout
DesiredSize = default;
// All changes to visibility cause the parent element to be notified.
this.GetVisualParent<ILayoutable>()?.ChildDesiredSizeChanged(this);
this.GetVisualParent<Layoutable>()?.ChildDesiredSizeChanged(this);
// We only invalidate outselves when visibility is changed to true.
if (change.GetNewValue<bool>())
@ -789,7 +786,7 @@ namespace Avalonia.Layout
}
/// <inheritdoc/>
protected sealed override void OnVisualParentChanged(IVisual? oldParent, IVisual? newParent)
protected sealed override void OnVisualParentChanged(Visual? oldParent, Visual? newParent)
{
LayoutHelper.InvalidateSelfAndChildrenMeasure(this);

4
src/Avalonia.Base/Layout/NonVirtualizingLayoutContext.cs

@ -17,13 +17,13 @@ namespace Avalonia.Layout
/// <summary>
/// Gets the collection of child controls from the container that provides the context.
/// </summary>
public IReadOnlyList<ILayoutable> Children => ChildrenCore;
public IReadOnlyList<Layoutable> Children => ChildrenCore;
/// <summary>
/// Implements the behavior for getting the return value of <see cref="Children"/> in a
/// derived or custom <see cref="NonVirtualizingLayoutContext"/>.
/// </summary>
protected abstract IReadOnlyList<ILayoutable> ChildrenCore { get; }
protected abstract IReadOnlyList<Layoutable> ChildrenCore { get; }
internal VirtualizingLayoutContext GetVirtualizingContextAdapter() =>
_contextAdapter ??= new LayoutContextAdapter(this);

8
src/Avalonia.Base/Layout/NonVirtualizingStackLayout.cs

@ -59,7 +59,7 @@ namespace Avalonia.Layout
{
var element = context.Children[i];
if (!element.IsVisible)
if ((element as Visual)?.IsVisible == false)
{
continue;
}
@ -100,7 +100,7 @@ namespace Avalonia.Layout
{
var element = context.Children[i];
if (!element.IsVisible)
if ((element as Visual)?.IsVisible == false)
{
continue;
}
@ -117,7 +117,7 @@ namespace Avalonia.Layout
Math.Max(finalSize.Height, bounds.Height));
}
private static Rect LayoutVertical(ILayoutable element, double y, Size constraint)
private static Rect LayoutVertical(Layoutable element, double y, Size constraint)
{
var x = 0.0;
var width = element.DesiredSize.Width;
@ -138,7 +138,7 @@ namespace Avalonia.Layout
return new Rect(x, y, width, element.DesiredSize.Height);
}
private static Rect LayoutHorizontal(ILayoutable element, double x, Size constraint)
private static Rect LayoutHorizontal(Layoutable element, double x, Size constraint)
{
var y = 0.0;
var height = element.DesiredSize.Height;

12
src/Avalonia.Base/Layout/StackLayout.cs

@ -78,10 +78,10 @@ namespace Avalonia.Layout
internal Rect GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable? firstRealized,
Layoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable? lastRealized,
Layoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds)
{
@ -121,7 +121,7 @@ namespace Avalonia.Layout
}
internal void OnElementMeasured(
ILayoutable element,
Layoutable element,
int index,
Size availableSize,
Size measureSize,
@ -188,10 +188,10 @@ namespace Avalonia.Layout
Rect IFlowLayoutAlgorithmDelegates.Algorithm_GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable? firstRealized,
Layoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable? lastRealized,
Layoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds)
{
@ -206,7 +206,7 @@ namespace Avalonia.Layout
lastRealizedLayoutBounds);
}
void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(ILayoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(Layoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
{
OnElementMeasured(
element,

6
src/Avalonia.Base/Layout/UniformGridLayout.cs

@ -338,10 +338,10 @@ namespace Avalonia.Layout
Rect IFlowLayoutAlgorithmDelegates.Algorithm_GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable? firstRealized,
Layoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable? lastRealized,
Layoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds)
{
@ -391,7 +391,7 @@ namespace Avalonia.Layout
return extent;
}
void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(ILayoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(Layoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
{
}

4
src/Avalonia.Base/Layout/UniformGridLayoutState.cs

@ -18,7 +18,7 @@ namespace Avalonia.Layout
// If it does not, then we need to do context.GetElement(0) at which point we have requested an element and are on point to clear it.
// If we are responsible for clearing element 0 we keep m_cachedFirstElement valid.
// If we are not (because FlowLayoutAlgorithm is holding it for us) then we just null out this field and use the one from FlowLayoutAlgorithm.
private ILayoutable? _cachedFirstElement;
private Layoutable? _cachedFirstElement;
internal FlowLayoutAlgorithm FlowAlgorithm { get; } = new FlowLayoutAlgorithm();
internal double EffectiveItemWidth { get; private set; }
@ -91,7 +91,7 @@ namespace Avalonia.Layout
}
private void SetSize(
ILayoutable element,
Layoutable element,
double layoutItemWidth,
double layoutItemHeight,
Size availableSize,

8
src/Avalonia.Base/Layout/VirtualLayoutContextAdapter.cs

@ -19,18 +19,18 @@ namespace Avalonia.Layout
set => _virtualizingContext.LayoutState = value;
}
protected override IReadOnlyList<ILayoutable> ChildrenCore =>
protected override IReadOnlyList<Layoutable> ChildrenCore =>
_children ?? (_children = new ChildrenCollection(_virtualizingContext));
private class ChildrenCollection : IReadOnlyList<ILayoutable>
private class ChildrenCollection : IReadOnlyList<Layoutable>
{
private readonly VirtualizingLayoutContext _context;
public ChildrenCollection(VirtualizingLayoutContext context) => _context = context;
public ILayoutable this[int index] => _context.GetOrCreateElementAt(index);
public Layoutable this[int index] => _context.GetOrCreateElementAt(index);
public int Count => _context.ItemCount;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<ILayoutable> GetEnumerator()
public IEnumerator<Layoutable> GetEnumerator()
{
for (var i = 0; i < Count; ++i)
{

12
src/Avalonia.Base/Layout/VirtualizingLayoutContext.cs

@ -116,7 +116,7 @@ namespace Avalonia.Layout
/// This method calls <see cref="GetOrCreateElementAtCore(int, ElementRealizationOptions)"/>
/// with options set to None. GetElementAtCore must be implemented in a derived class.
/// </remarks>
public ILayoutable GetOrCreateElementAt(int index)
public Layoutable GetOrCreateElementAt(int index)
=> GetOrCreateElementAtCore(index, ElementRealizationOptions.None);
/// <summary>
@ -140,7 +140,7 @@ namespace Avalonia.Layout
/// advanced layouts that choose to explicitly manage the realization and recycling of
/// elements as a performance optimization.
/// </remarks>
public ILayoutable GetOrCreateElementAt(int index, ElementRealizationOptions options)
public Layoutable GetOrCreateElementAt(int index, ElementRealizationOptions options)
=> GetOrCreateElementAtCore(index, options);
/// <summary>
@ -148,10 +148,10 @@ namespace Avalonia.Layout
/// </summary>
/// <param name="element">The element to clear.</param>
/// <remarks>
/// This method calls <see cref="RecycleElementCore(ILayoutable)"/>, which must be implemented
/// This method calls <see cref="RecycleElementCore(Layoutable)"/>, which must be implemented
/// in a derived class.
/// </remarks>
public void RecycleElement(ILayoutable element) => RecycleElementCore(element);
public void RecycleElement(Layoutable element) => RecycleElementCore(element);
/// <summary>
/// When implemented in a derived class, retrieves the number of items in the data.
@ -180,14 +180,14 @@ namespace Avalonia.Layout
/// A value of <see cref="ElementRealizationOptions"/> that specifies whether to suppress
/// automatic recycling of the retrieved element or force creation of a new element.
/// </param>
protected abstract ILayoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options);
protected abstract Layoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options);
/// <summary>
/// When implemented in a derived class, clears the specified UIElement and allows it to be
/// either re-used or released.
/// </summary>
/// <param name="element">The element to clear.</param>
protected abstract void RecycleElementCore(ILayoutable element);
protected abstract void RecycleElementCore(Layoutable element);
internal NonVirtualizingLayoutContext GetNonVirtualizingContextAdapter() =>
_contextAdapter ?? (_contextAdapter = new VirtualLayoutContextAdapter(this));

2
src/Avalonia.Base/Layout/WrapLayout/WrapItem.cs

@ -20,6 +20,6 @@ namespace Avalonia.Layout
public UvMeasure? Position { get; internal set; }
public ILayoutable? Element { get; internal set; }
public Layoutable? Element { get; internal set; }
}
}

4
src/Avalonia.Base/Media/IVisualBrush.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media
{
/// <summary>
/// Paints an area with an <see cref="IVisual"/>.
/// Paints an area with an <see cref="Visual"/>.
/// </summary>
[NotClientImplementable]
public interface IVisualBrush : ITileBrush
@ -12,6 +12,6 @@ namespace Avalonia.Media
/// <summary>
/// Gets the visual to draw.
/// </summary>
IVisual Visual { get; }
Visual Visual { get; }
}
}

2
src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs

@ -44,7 +44,7 @@ namespace Avalonia.Media.Imaging
/// Renders a visual to the <see cref="RenderTargetBitmap"/>.
/// </summary>
/// <param name="visual">The visual to render.</param>
public void Render(IVisual visual) => ImmediateRenderer.Render(visual, this);
public void Render(Visual visual) => ImmediateRenderer.Render(visual, this);
/// <summary>
/// Creates a platform-specific implementation for a <see cref="RenderTargetBitmap"/>.

4
src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs

@ -25,7 +25,7 @@ namespace Avalonia.Media.Immutable
/// <param name="tileMode">The tile mode.</param>
/// <param name="bitmapInterpolationMode">Controls the quality of interpolation.</param>
public ImmutableVisualBrush(
IVisual visual,
Visual visual,
AlignmentX alignmentX = AlignmentX.Center,
AlignmentY alignmentY = AlignmentY.Center,
RelativeRect? destinationRect = null,
@ -62,6 +62,6 @@ namespace Avalonia.Media.Immutable
}
/// <inheritdoc/>
public IVisual Visual { get; }
public Visual Visual { get; }
}
}

10
src/Avalonia.Base/Media/VisualBrush.cs

@ -4,15 +4,15 @@ using Avalonia.VisualTree;
namespace Avalonia.Media
{
/// <summary>
/// Paints an area with an <see cref="IVisual"/>.
/// Paints an area with an <see cref="Visual"/>.
/// </summary>
public class VisualBrush : TileBrush, IVisualBrush
{
/// <summary>
/// Defines the <see cref="Visual"/> property.
/// </summary>
public static readonly StyledProperty<IVisual> VisualProperty =
AvaloniaProperty.Register<VisualBrush, IVisual>(nameof(Visual));
public static readonly StyledProperty<Visual> VisualProperty =
AvaloniaProperty.Register<VisualBrush, Visual>(nameof(Visual));
static VisualBrush()
{
@ -30,7 +30,7 @@ namespace Avalonia.Media
/// Initializes a new instance of the <see cref="VisualBrush"/> class.
/// </summary>
/// <param name="visual">The visual to draw.</param>
public VisualBrush(IVisual visual)
public VisualBrush(Visual visual)
{
Visual = visual;
}
@ -38,7 +38,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets the visual to draw.
/// </summary>
public IVisual Visual
public Visual Visual
{
get { return GetValue(VisualProperty); }
set { SetValue(VisualProperty, value); }

2
src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs

@ -262,7 +262,7 @@ namespace Avalonia.PropertyStore
private class UncommonFields
{
public Func<IAvaloniaObject, T, T>? _coerce;
public Func<AvaloniaObject, T, T>? _coerce;
public T? _uncoercedValue;
public T? _uncoercedBaseValue;
}

12
src/Avalonia.Base/PropertyStore/UntypedValueUtils.cs

@ -23,18 +23,6 @@ namespace Avalonia.PropertyStore
return v;
}
public static bool TryConvertAndValidate(
AvaloniaProperty property,
object? value,
out object? result)
{
if (TypeUtilities.TryConvertImplicit(property.PropertyType, value, out result))
return ((IStyledPropertyAccessor)property).ValidateValue(result);
result = default;
return false;
}
public static bool TryConvertAndValidate<T>(
StyledPropertyBase<T> property,
object? value,

6
src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs

@ -6,15 +6,15 @@ namespace Avalonia.Reactive
{
internal class AvaloniaPropertyBindingObservable<T> : LightweightObservableBase<BindingValue<T>>, IDescription
{
private readonly WeakReference<IAvaloniaObject> _target;
private readonly WeakReference<AvaloniaObject> _target;
private readonly AvaloniaProperty _property;
private BindingValue<T> _value = BindingValue<T>.Unset;
public AvaloniaPropertyBindingObservable(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty property)
{
_target = new WeakReference<IAvaloniaObject>(target);
_target = new WeakReference<AvaloniaObject>(target);
_property = property;
}

6
src/Avalonia.Base/Reactive/AvaloniaPropertyChangedObservable.cs

@ -6,14 +6,14 @@ namespace Avalonia.Reactive
LightweightObservableBase<AvaloniaPropertyChangedEventArgs>,
IDescription
{
private readonly WeakReference<IAvaloniaObject> _target;
private readonly WeakReference<AvaloniaObject> _target;
private readonly AvaloniaProperty _property;
public AvaloniaPropertyChangedObservable(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty property)
{
_target = new WeakReference<IAvaloniaObject>(target);
_target = new WeakReference<AvaloniaObject>(target);
_property = property;
}

36
src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs

@ -6,15 +6,15 @@ namespace Avalonia.Reactive
{
internal class AvaloniaPropertyObservable<T> : LightweightObservableBase<T>, IDescription
{
private readonly WeakReference<IAvaloniaObject> _target;
private readonly WeakReference<AvaloniaObject> _target;
private readonly AvaloniaProperty _property;
private Optional<T> _value;
public AvaloniaPropertyObservable(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty property)
{
_target = new WeakReference<IAvaloniaObject>(target);
_target = new WeakReference<AvaloniaObject>(target);
_property = property;
}
@ -49,31 +49,23 @@ namespace Avalonia.Reactive
{
if (e.Property == _property)
{
if (e.Sender is AvaloniaObject ao)
{
T newValue;
if (e is AvaloniaPropertyChangedEventArgs<T> typed)
{
newValue = AvaloniaObjectExtensions.GetValue(ao, typed.Property);
}
else
{
newValue = (T)e.Sender.GetValue(e.Property)!;
}
T newValue;
if (!_value.HasValue ||
!EqualityComparer<T>.Default.Equals(newValue, _value.Value))
{
_value = newValue;
PublishNext(_value.Value!);
}
if (e is AvaloniaPropertyChangedEventArgs<T> typed)
{
newValue = AvaloniaObjectExtensions.GetValue(e.Sender, typed.Property);
}
else
{
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
newValue = (T)e.Sender.GetValue(e.Property)!;
}
if (!_value.HasValue ||
!EqualityComparer<T>.Default.Equals(newValue, _value.Value))
{
_value = newValue;
PublishNext(_value.Value!);
}
}
}
}

14
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -45,7 +45,7 @@ public class CompositingRenderer : IRendererWithCompositor
_compositor = compositor;
_recordingContext = new DrawingContext(_recorder);
CompositionTarget = compositor.CreateCompositionTarget(root.CreateRenderTarget);
CompositionTarget.Root = ((Visual)root!.VisualRoot!).AttachToCompositor(compositor);
CompositionTarget.Root = ((Visual)root).AttachToCompositor(compositor);
_update = Update;
}
@ -75,7 +75,7 @@ public class CompositingRenderer : IRendererWithCompositor
}
/// <inheritdoc/>
public void AddDirty(IVisual visual)
public void AddDirty(Visual visual)
{
if (_updating)
throw new InvalidOperationException("Visual was invalidated during the render pass");
@ -84,7 +84,7 @@ public class CompositingRenderer : IRendererWithCompositor
}
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool>? filter)
{
Func<CompositionVisual, bool>? f = null;
if (filter != null)
@ -109,14 +109,14 @@ public class CompositingRenderer : IRendererWithCompositor
}
/// <inheritdoc/>
public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool>? filter)
{
// TODO: Optimize
return HitTest(p, root, filter).FirstOrDefault();
}
/// <inheritdoc/>
public void RecalculateChildren(IVisual visual)
public void RecalculateChildren(Visual visual)
{
if (_updating)
throw new InvalidOperationException("Visual was invalidated during the render pass");
@ -130,9 +130,9 @@ public class CompositingRenderer : IRendererWithCompositor
if(v.CompositionVisual == null)
return;
var compositionChildren = v.CompositionVisual.Children;
var visualChildren = (AvaloniaList<IVisual>)v.GetVisualChildren();
var visualChildren = (AvaloniaList<Visual>)v.GetVisualChildren();
PooledList<(IVisual visual, int index)>? sortedChildren = null;
PooledList<(Visual visual, int index)>? sortedChildren = null;
if (v.HasNonUniformZIndexChildren && visualChildren.Count > 1)
{
sortedChildren = new (visualChildren.Count);

22
src/Avalonia.Base/Rendering/DeferredRenderer.cs

@ -22,14 +22,14 @@ namespace Avalonia.Rendering
{
private readonly IDispatcher? _dispatcher;
private readonly IRenderLoop? _renderLoop;
private readonly IVisual _root;
private readonly Visual _root;
private readonly ISceneBuilder _sceneBuilder;
private bool _running;
private bool _disposed;
private volatile IRef<Scene>? _scene;
private DirtyVisuals? _dirty;
private HashSet<IVisual>? _recalculateChildren;
private HashSet<Visual>? _recalculateChildren;
private IRef<IRenderTargetBitmapImpl>? _overlay;
private int _lastSceneId = -1;
private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
@ -56,7 +56,7 @@ namespace Avalonia.Rendering
IDeferredRendererLock? rendererLock = null) : base(true)
{
_dispatcher = dispatcher ?? Dispatcher.UIThread;
_root = root ?? throw new ArgumentNullException(nameof(root));
_root = root as Visual ?? throw new ArgumentNullException(nameof(root));
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers();
_renderLoop = renderLoop;
@ -74,7 +74,7 @@ namespace Avalonia.Rendering
/// This constructor is intended to be used for unit testing.
/// </remarks>
public DeferredRenderer(
IVisual root,
Visual root,
IRenderTarget renderTarget,
ISceneBuilder? sceneBuilder = null) : base(true)
{
@ -116,7 +116,7 @@ namespace Avalonia.Rendering
internal IRenderTarget? RenderTarget { get; private set; }
/// <inheritdoc/>
public void AddDirty(IVisual visual)
public void AddDirty(Visual visual)
{
_dirty?.Add(visual);
}
@ -142,7 +142,7 @@ namespace Avalonia.Rendering
DisposeRenderTarget();
}
public void RecalculateChildren(IVisual visual) => _recalculateChildren?.Add(visual);
public void RecalculateChildren(Visual visual) => _recalculateChildren?.Add(visual);
void DisposeRenderTarget()
{
@ -163,17 +163,17 @@ namespace Avalonia.Rendering
}
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool>? filter)
{
EnsureCanHitTest();
//It's safe to access _scene here without a lock since
//it's only changed from UI thread which we are currently on
return _scene?.Item.HitTest(p, root, filter) ?? Enumerable.Empty<IVisual>();
return _scene?.Item.HitTest(p, root, filter) ?? Enumerable.Empty<Visual>();
}
/// <inheritdoc/>
public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool>? filter)
{
EnsureCanHitTest();
@ -414,7 +414,7 @@ namespace Avalonia.Rendering
}
private void Render(IDrawingContextImpl context, VisualNode node, IVisual? layer, Rect clipBounds)
private void Render(IDrawingContextImpl context, VisualNode node, Visual? layer, Rect clipBounds)
{
if (layer == null || node.LayerRoot == layer)
{
@ -643,7 +643,7 @@ namespace Avalonia.Rendering
if (_dirty == null)
{
_dirty = new DirtyVisuals();
_recalculateChildren = new HashSet<IVisual>();
_recalculateChildren = new HashSet<Visual>();
_sceneBuilder.UpdateAll(scene);
}
else

14
src/Avalonia.Base/Rendering/DirtyVisuals.cs

@ -13,10 +13,10 @@ namespace Avalonia.Rendering
/// visual. TODO: We probably want to put an upper limit on the number of visuals that can be
/// stored and if we reach that limit, assume all visuals are dirty.
/// </remarks>
internal class DirtyVisuals : IEnumerable<IVisual>
internal class DirtyVisuals : IEnumerable<Visual>
{
private SortedDictionary<int, List<IVisual>> _inner = new SortedDictionary<int, List<IVisual>>();
private Dictionary<IVisual, int> _index = new Dictionary<IVisual, int>();
private SortedDictionary<int, List<Visual>> _inner = new SortedDictionary<int, List<Visual>>();
private Dictionary<Visual, int> _index = new Dictionary<Visual, int>();
private int _enumerating;
/// <summary>
@ -28,14 +28,14 @@ namespace Avalonia.Rendering
/// Adds a visual to the dirty list.
/// </summary>
/// <param name="visual">The dirty visual.</param>
public void Add(IVisual visual)
public void Add(Visual visual)
{
if (_enumerating > 0)
{
throw new InvalidOperationException("Visual was invalidated during a render pass");
}
var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot);
var distance = visual.CalculateDistanceFromAncestor((Visual?)visual.GetVisualRoot());
if (_index.TryGetValue(visual, out var existingDistance))
{
@ -50,7 +50,7 @@ namespace Avalonia.Rendering
if (!_inner.TryGetValue(distance, out var list))
{
list = new List<IVisual>();
list = new List<Visual>();
_inner.Add(distance, list);
}
@ -76,7 +76,7 @@ namespace Avalonia.Rendering
/// Gets the dirty visuals, in ascending order of distance to their root.
/// </summary>
/// <returns>A collection of visuals.</returns>
public IEnumerator<IVisual> GetEnumerator()
public IEnumerator<Visual> GetEnumerator()
{
_enumerating++;
try

4
src/Avalonia.Base/Rendering/ICustomSimpleHitTest.cs

@ -24,10 +24,10 @@ namespace Avalonia.Rendering
public static class CustomSimpleHitTestExtensions
{
public static bool HitTestCustom(this IVisual visual, Point point)
public static bool HitTestCustom(this Visual visual, Point point)
=> (visual as ICustomSimpleHitTest)?.HitTest(point) ?? visual.TransformedBounds?.Contains(point) == true;
public static bool HitTestCustom(this IEnumerable<IVisual> children, Point point)
public static bool HitTestCustom(this IEnumerable<Visual> children, Point point)
=> children.Any(ctrl => ctrl.HitTestCustom(point));
}
}

2
src/Avalonia.Base/Rendering/IRenderRoot.cs

@ -8,7 +8,7 @@ namespace Avalonia.Rendering
/// Represents the root of a renderable tree.
/// </summary>
[NotClientImplementable]
public interface IRenderRoot : IVisual
public interface IRenderRoot
{
/// <summary>
/// Gets the client size of the window.

8
src/Avalonia.Base/Rendering/IRenderer.cs

@ -34,7 +34,7 @@ namespace Avalonia.Rendering
/// Mark a visual as dirty and needing re-rendering.
/// </summary>
/// <param name="visual">The visual.</param>
void AddDirty(IVisual visual);
void AddDirty(Visual visual);
/// <summary>
/// Hit tests a location to find the visuals at the specified point.
@ -46,7 +46,7 @@ namespace Avalonia.Rendering
/// children will be excluded from the results.
/// </param>
/// <returns>The visuals at the specified point, topmost first.</returns>
IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter);
IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool> filter);
/// <summary>
/// Hit tests a location to find first visual at the specified point.
@ -58,13 +58,13 @@ namespace Avalonia.Rendering
/// children will be excluded from the results.
/// </param>
/// <returns>The visual at the specified point, topmost first.</returns>
IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter);
Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool> filter);
/// <summary>
/// Informs the renderer that the z-ordering of a visual's children has changed.
/// </summary>
/// <param name="visual">The visual.</param>
void RecalculateChildren(IVisual visual);
void RecalculateChildren(Visual visual);
/// <summary>
/// Called when a resize notification is received by the control being rendered.

38
src/Avalonia.Base/Rendering/ImmediateRenderer.cs

@ -18,7 +18,7 @@ namespace Avalonia.Rendering
/// </remarks>
public class ImmediateRenderer : RendererBase, IRenderer, IVisualBrushRenderer
{
private readonly IVisual _root;
private readonly Visual _root;
private readonly IRenderRoot? _renderRoot;
private bool _updateTransformedBounds = true;
private IRenderTarget? _renderTarget;
@ -27,13 +27,13 @@ namespace Avalonia.Rendering
/// Initializes a new instance of the <see cref="ImmediateRenderer"/> class.
/// </summary>
/// <param name="root">The control to render.</param>
public ImmediateRenderer(IVisual root)
public ImmediateRenderer(Visual root)
{
_root = root ?? throw new ArgumentNullException(nameof(root));
_renderRoot = root as IRenderRoot;
}
private ImmediateRenderer(IVisual root, bool updateTransformedBounds)
private ImmediateRenderer(Visual root, bool updateTransformedBounds)
{
_root = root ?? throw new ArgumentNullException(nameof(root));
_renderRoot = root as IRenderRoot;
@ -102,7 +102,7 @@ namespace Avalonia.Rendering
/// </summary>
/// <param name="visual">The visual.</param>
/// <param name="target">The render target.</param>
public static void Render(IVisual visual, IRenderTarget target)
public static void Render(Visual visual, IRenderTarget target)
{
using (var renderer = new ImmediateRenderer(visual, updateTransformedBounds: false))
using (var context = new DrawingContext(target.CreateDrawingContext(renderer)))
@ -116,7 +116,7 @@ namespace Avalonia.Rendering
/// </summary>
/// <param name="visual">The visual.</param>
/// <param name="context">The drawing context.</param>
public static void Render(IVisual visual, DrawingContext context)
public static void Render(Visual visual, DrawingContext context)
{
using (var renderer = new ImmediateRenderer(visual, updateTransformedBounds: false))
{
@ -125,7 +125,7 @@ namespace Avalonia.Rendering
}
/// <inheritdoc/>
public void AddDirty(IVisual visual)
public void AddDirty(Visual visual)
{
if (visual.Bounds != Rect.Empty)
{
@ -162,18 +162,18 @@ namespace Avalonia.Rendering
}
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool> filter)
{
return HitTest(root, p, filter);
}
public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter)
public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool> filter)
{
return HitTest(root, p, filter).FirstOrDefault();
}
/// <inheritdoc/>
public void RecalculateChildren(IVisual visual) => AddDirty(visual);
public void RecalculateChildren(Visual visual) => AddDirty(visual);
/// <inheritdoc/>
public void Start()
@ -199,21 +199,21 @@ namespace Avalonia.Rendering
Render(new DrawingContext(context), visual, visual.Bounds);
}
internal static void Render(IVisual visual, DrawingContext context, bool updateTransformedBounds)
internal static void Render(Visual visual, DrawingContext context, bool updateTransformedBounds)
{
using var renderer = new ImmediateRenderer(visual, updateTransformedBounds);
renderer.Render(context, visual, visual.Bounds);
}
private static void ClearTransformedBounds(IVisual visual)
private static void ClearTransformedBounds(Visual visual)
{
foreach (var e in visual.GetSelfAndVisualDescendants())
{
visual.TransformedBounds = null;
visual.SetTransformedBounds(null);
}
}
private static Rect GetTransformedBounds(IVisual visual)
private static Rect GetTransformedBounds(Visual visual)
{
if (visual.RenderTransform == null)
{
@ -228,10 +228,10 @@ namespace Avalonia.Rendering
}
}
private static IEnumerable<IVisual> HitTest(
IVisual visual,
private static IEnumerable<Visual> HitTest(
Visual visual,
Point p,
Func<IVisual, bool>? filter)
Func<Visual, bool>? filter)
{
_ = visual ?? throw new ArgumentNullException(nameof(visual));
@ -266,7 +266,7 @@ namespace Avalonia.Rendering
}
}
private void Render(DrawingContext context, IVisual visual, Rect clipRect)
private void Render(DrawingContext context, Visual visual, Rect clipRect)
{
var opacity = visual.Opacity;
var clipToBounds = visual.ClipToBounds;
@ -329,11 +329,11 @@ namespace Avalonia.Rendering
#pragma warning restore 0618
if (_updateTransformedBounds)
visual.TransformedBounds = transformed;
visual.SetTransformedBounds(transformed);
var childrenEnumerable = visual.HasNonUniformZIndexChildren
? visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance)
: (IEnumerable<IVisual>)visual.VisualChildren;
: (IEnumerable<Visual>)visual.VisualChildren;
foreach (var child in childrenEnumerable)
{

4
src/Avalonia.Base/Rendering/RenderLayer.cs

@ -11,7 +11,7 @@ namespace Avalonia.Rendering
IDrawingContextImpl drawingContext,
Size size,
double scaling,
IVisual layerRoot)
Visual layerRoot)
{
Bitmap = RefCountable.Create(drawingContext.CreateLayer(size));
Size = size;
@ -24,7 +24,7 @@ namespace Avalonia.Rendering
public bool IsEmpty { get; set; }
public double Scaling { get; private set; }
public Size Size { get; private set; }
public IVisual LayerRoot { get; }
public Visual LayerRoot { get; }
public void RecreateBitmap(IDrawingContextImpl drawingContext, Size size, double scaling)
{

7
src/Avalonia.Base/Rendering/RenderLayers.cs

@ -3,17 +3,16 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.VisualTree;
namespace Avalonia.Rendering
{
public class RenderLayers : IEnumerable<RenderLayer>
{
private readonly List<RenderLayer> _inner = new List<RenderLayer>();
private readonly Dictionary<IVisual, RenderLayer> _index = new Dictionary<IVisual, RenderLayer>();
private readonly Dictionary<Visual, RenderLayer> _index = new Dictionary<Visual, RenderLayer>();
public int Count => _inner.Count;
public RenderLayer this[IVisual layerRoot] => _index[layerRoot];
public RenderLayer this[Visual layerRoot] => _index[layerRoot];
public void Update(Scene scene, IDrawingContextImpl context)
{
@ -59,7 +58,7 @@ namespace Avalonia.Rendering
_inner.Clear();
}
public bool TryGetValue(IVisual layerRoot, [NotNullWhen(true)] out RenderLayer? value)
public bool TryGetValue(Visual layerRoot, [NotNullWhen(true)] out RenderLayer? value)
{
return _index.TryGetValue(layerRoot, out value);
}

4
src/Avalonia.Base/Rendering/SceneGraph/ISceneBuilder.cs

@ -19,6 +19,6 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="scene">The scene.</param>
/// <param name="visual">The visual to update.</param>
/// <returns>True if changes were made, otherwise false.</returns>
bool Update(Scene scene, IVisual visual);
bool Update(Scene scene, Visual visual);
}
}
}

5
src/Avalonia.Base/Rendering/SceneGraph/IVisualNode.cs

@ -2,19 +2,18 @@
using System.Collections.Generic;
using Avalonia.Platform;
using Avalonia.Utilities;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
/// <summary>
/// Represents a node in the low-level scene graph representing an <see cref="IVisual"/>.
/// Represents a node in the low-level scene graph representing a <see cref="Visual"/>.
/// </summary>
public interface IVisualNode : IDisposable
{
/// <summary>
/// Gets the visual to which the node relates.
/// </summary>
IVisual Visual { get; }
Visual Visual { get; }
/// <summary>
/// Gets the parent scene graph node.

40
src/Avalonia.Base/Rendering/SceneGraph/Scene.cs

@ -13,24 +13,24 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
public class Scene : IDisposable
{
private readonly Dictionary<IVisual, IVisualNode> _index;
private readonly Dictionary<Visual, IVisualNode> _index;
private readonly TaskCompletionSource<bool> _rendered = new TaskCompletionSource<bool>();
/// <summary>
/// Initializes a new instance of the <see cref="Scene"/> class.
/// </summary>
/// <param name="rootVisual">The root visual to draw.</param>
public Scene(IVisual rootVisual)
public Scene(Visual rootVisual)
: this(
new VisualNode(rootVisual, null),
new Dictionary<IVisual, IVisualNode>(),
new Dictionary<Visual, IVisualNode>(),
new SceneLayers(rootVisual),
0)
{
_index.Add(rootVisual, Root);
}
private Scene(VisualNode root, Dictionary<IVisual, IVisualNode> index, SceneLayers layers, int generation)
private Scene(VisualNode root, Dictionary<Visual, IVisualNode> index, SceneLayers layers, int generation)
{
_ = root ?? throw new ArgumentNullException(nameof(root));
@ -87,7 +87,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <returns>The cloned scene.</returns>
public Scene CloneScene()
{
var index = new Dictionary<IVisual, IVisualNode>(_index.Count);
var index = new Dictionary<Visual, IVisualNode>(_index.Count);
var root = Clone((VisualNode)Root, null, index);
var result = new Scene(root, index, Layers.Clone(), Generation + 1)
@ -115,7 +115,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <returns>
/// The node representing the visual or null if it could not be found.
/// </returns>
public IVisualNode? FindNode(IVisual visual)
public IVisualNode? FindNode(Visual visual)
{
_index.TryGetValue(visual, out var node);
return node;
@ -128,10 +128,10 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="root">The root of the subtree to search.</param>
/// <param name="filter">A filter. May be null.</param>
/// <returns>The visuals at the specified point.</returns>
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool>? filter)
{
var node = FindNode(root);
return (node != null) ? new HitTestEnumerable(node, filter, p, Root) : Enumerable.Empty<IVisual>();
return (node != null) ? new HitTestEnumerable(node, filter, p, Root) : Enumerable.Empty<Visual>();
}
/// <summary>
@ -141,7 +141,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="root">The root of the subtree to search.</param>
/// <param name="filter">A filter. May be null.</param>
/// <returns>The visual at the specified point.</returns>
public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool>? filter)
{
var node = FindNode(root);
return (node != null) ? HitTestFirst(node, p, filter) : null;
@ -160,7 +160,7 @@ namespace Avalonia.Rendering.SceneGraph
node.Dispose();
}
private VisualNode Clone(VisualNode source, IVisualNode? parent, Dictionary<IVisual, IVisualNode> index)
private VisualNode Clone(VisualNode source, IVisualNode? parent, Dictionary<Visual, IVisualNode> index)
{
var result = source.Clone(parent);
@ -184,7 +184,7 @@ namespace Avalonia.Rendering.SceneGraph
return result;
}
private IVisual HitTestFirst(IVisualNode root, Point p, Func<IVisual, bool>? filter)
private Visual HitTestFirst(IVisualNode root, Point p, Func<Visual, bool>? filter)
{
using var enumerator = new HitTestEnumerator(root, filter, p, Root);
@ -193,14 +193,14 @@ namespace Avalonia.Rendering.SceneGraph
return enumerator.Current;
}
private class HitTestEnumerable : IEnumerable<IVisual>
private class HitTestEnumerable : IEnumerable<Visual>
{
private readonly IVisualNode _root;
private readonly Func<IVisual, bool>? _filter;
private readonly Func<Visual, bool>? _filter;
private readonly IVisualNode _sceneRoot;
private readonly Point _point;
public HitTestEnumerable(IVisualNode root, Func<IVisual, bool>? filter, Point point, IVisualNode sceneRoot)
public HitTestEnumerable(IVisualNode root, Func<Visual, bool>? filter, Point point, IVisualNode sceneRoot)
{
_root = root;
_filter = filter;
@ -208,7 +208,7 @@ namespace Avalonia.Rendering.SceneGraph
_sceneRoot = sceneRoot;
}
public IEnumerator<IVisual> GetEnumerator()
public IEnumerator<Visual> GetEnumerator()
{
return new HitTestEnumerator(_root, _filter, _point, _sceneRoot);
}
@ -219,15 +219,15 @@ namespace Avalonia.Rendering.SceneGraph
}
}
private struct HitTestEnumerator : IEnumerator<IVisual>
private struct HitTestEnumerator : IEnumerator<Visual>
{
private readonly PooledStack<Entry> _nodeStack;
private readonly Func<IVisual, bool>? _filter;
private readonly Func<Visual, bool>? _filter;
private readonly IVisualNode _sceneRoot;
private IVisual? _current;
private Visual? _current;
private readonly Point _point;
public HitTestEnumerator(IVisualNode root, Func<IVisual, bool>? filter, Point point, IVisualNode sceneRoot)
public HitTestEnumerator(IVisualNode root, Func<Visual, bool>? filter, Point point, IVisualNode sceneRoot)
{
_nodeStack = new PooledStack<Entry>();
_nodeStack.Push(new Entry(root, false, null, true));
@ -282,7 +282,7 @@ namespace Avalonia.Rendering.SceneGraph
throw new NotSupportedException();
}
public IVisual Current => _current!;
public Visual Current => _current!;
object IEnumerator.Current => Current;

18
src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs

@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public bool Update(Scene scene, IVisual visual)
public bool Update(Scene scene, Visual visual)
{
_ = scene ?? throw new ArgumentNullException(nameof(scene));
_ = visual ?? throw new ArgumentNullException(nameof(visual));
@ -120,7 +120,7 @@ namespace Avalonia.Rendering.SceneGraph
return false;
}
private static VisualNode? FindExistingAncestor(Scene scene, IVisual visual)
private static VisualNode? FindExistingAncestor(Scene scene, Visual visual)
{
var node = scene.FindNode(visual);
@ -151,7 +151,7 @@ namespace Avalonia.Rendering.SceneGraph
return (VisualNode)node;
}
private static object GetOrCreateChildNode(Scene scene, IVisual child, VisualNode parent)
private static object GetOrCreateChildNode(Scene scene, Visual child, VisualNode parent)
{
var result = (VisualNode?)scene.FindNode(child);
@ -259,11 +259,11 @@ namespace Avalonia.Rendering.SceneGraph
catch { }
var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
visual.TransformedBounds = transformed;
visual.SetTransformedBounds(transformed);
if (forceRecurse)
{
var visualChildren = (IList<IVisual>) visual.VisualChildren;
var visualChildren = (IList<Visual>) visual.VisualChildren;
node.TryPreallocateChildren(visualChildren.Count);
@ -278,7 +278,7 @@ namespace Avalonia.Rendering.SceneGraph
if (visual.HasNonUniformZIndexChildren)
{
var sortedChildren = new (IVisual visual, int index)[count];
var sortedChildren = new (Visual visual, int index)[count];
for (var i = 0; i < count; i++)
{
@ -352,7 +352,7 @@ namespace Avalonia.Rendering.SceneGraph
}
}
private static VisualNode CreateNode(Scene scene, IVisual visual, VisualNode parent)
private static VisualNode CreateNode(Scene scene, Visual visual, VisualNode parent)
{
var node = new VisualNode(visual, parent);
node.LayerRoot = parent.LayerRoot;
@ -379,7 +379,7 @@ namespace Avalonia.Rendering.SceneGraph
scene.Layers[node.LayerRoot!].Dirty.Add(node.Bounds);
node.Visual.TransformedBounds = null;
node.Visual.SetTransformedBounds(null);
if (node.LayerRoot == node.Visual && node.Visual != scene.Root.Visual)
{
@ -455,7 +455,7 @@ namespace Avalonia.Rendering.SceneGraph
}
// HACK: Disabled layers because they're broken in current renderer. See #2244.
private static bool ShouldStartLayer(IVisual visual) => false;
private static bool ShouldStartLayer(Visual visual) => false;
private static IGeometryImpl? CreateLayerGeometryClip(VisualNode node)
{

5
src/Avalonia.Base/Rendering/SceneGraph/SceneLayer.cs

@ -1,6 +1,5 @@
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
@ -14,7 +13,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="layerRoot">The visual at the root of the layer.</param>
/// <param name="distanceFromRoot">The distance from the scene root.</param>
public SceneLayer(IVisual layerRoot, int distanceFromRoot)
public SceneLayer(Visual layerRoot, int distanceFromRoot)
{
LayerRoot = layerRoot;
Dirty = new DirtyRects();
@ -39,7 +38,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <summary>
/// Gets the visual at the root of the layer.
/// </summary>
public IVisual LayerRoot { get; }
public Visual LayerRoot { get; }
/// <summary>
/// Gets the distance of the layer root from the root of the scene.

22
src/Avalonia.Base/Rendering/SceneGraph/SceneLayers.cs

@ -10,15 +10,15 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
public class SceneLayers : IEnumerable<SceneLayer>
{
private readonly IVisual _root;
private readonly Visual _root;
private readonly List<SceneLayer> _inner;
private readonly Dictionary<IVisual, SceneLayer> _index;
private readonly Dictionary<Visual, SceneLayer> _index;
/// <summary>
/// Initializes a new instance of the <see cref="SceneLayers"/> class.
/// </summary>
/// <param name="root">The scene's root visual.</param>
public SceneLayers(IVisual root) : this(root, 0)
public SceneLayers(Visual root) : this(root, 0)
{
}
@ -27,12 +27,12 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="root">The scene's root visual.</param>
/// <param name="capacity">Initial layer capacity.</param>
public SceneLayers(IVisual root, int capacity)
public SceneLayers(Visual root, int capacity)
{
_root = root;
_inner = new List<SceneLayer>(capacity);
_index = new Dictionary<IVisual, SceneLayer>(capacity);
_index = new Dictionary<Visual, SceneLayer>(capacity);
}
/// <summary>
@ -71,14 +71,14 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="visual">The layer's root visual.</param>
/// <returns>The layer.</returns>
public SceneLayer this[IVisual visual] => _index[visual];
public SceneLayer this[Visual visual] => _index[visual];
/// <summary>
/// Adds a layer to the scene.
/// </summary>
/// <param name="layerRoot">The root visual of the layer.</param>
/// <returns>The created layer.</returns>
public SceneLayer Add(IVisual layerRoot)
public SceneLayer Add(Visual layerRoot)
{
_ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
@ -115,7 +115,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <returns>
/// True if a layer exists with the specified root visual, otherwise false.
/// </returns>
public bool Exists(IVisual layerRoot)
public bool Exists(Visual layerRoot)
{
_ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
@ -127,7 +127,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="layerRoot">The root visual.</param>
/// <returns>The layer if found, otherwise null.</returns>
public SceneLayer? Find(IVisual layerRoot)
public SceneLayer? Find(Visual layerRoot)
{
_index.TryGetValue(layerRoot, out var result);
return result;
@ -138,7 +138,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="layerRoot">The root visual.</param>
/// <returns>The layer.</returns>
public SceneLayer GetOrAdd(IVisual layerRoot)
public SceneLayer GetOrAdd(Visual layerRoot)
{
_ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
@ -155,7 +155,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="layerRoot">The root visual.</param>
/// <returns>True if a matching layer was removed, otherwise false.</returns>
public bool Remove(IVisual layerRoot)
public bool Remove(Visual layerRoot)
{
_ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));

6
src/Avalonia.Base/Rendering/SceneGraph/VisualNode.cs

@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
/// <param name="visual">The visual that this node represents.</param>
/// <param name="parent">The parent scene graph node, if any.</param>
public VisualNode(IVisual visual, IVisualNode? parent)
public VisualNode(Visual visual, IVisualNode? parent)
{
Visual = visual ?? throw new ArgumentNullException(nameof(visual));
Parent = parent;
@ -39,7 +39,7 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public IVisual Visual { get; }
public Visual Visual { get; }
/// <inheritdoc/>
public IVisualNode? Parent { get; }
@ -98,7 +98,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
public bool OpacityChanged { get; private set; }
public IVisual? LayerRoot { get; set; }
public Visual? LayerRoot { get; set; }
/// <inheritdoc/>
public IReadOnlyList<IVisualNode> Children => _children ?? EmptyChildren;

6
src/Avalonia.Base/Rendering/ZIndexComparer.cs

@ -4,11 +4,11 @@ using Avalonia.VisualTree;
namespace Avalonia.Rendering
{
public class ZIndexComparer : IComparer<IVisual>
public class ZIndexComparer : IComparer<Visual>
{
public static readonly ZIndexComparer Instance = new ZIndexComparer();
public static readonly Comparison<IVisual> ComparisonInstance = Instance.Compare;
public static readonly Comparison<Visual> ComparisonInstance = Instance.Compare;
public int Compare(IVisual? x, IVisual? y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0);
public int Compare(Visual? x, Visual? y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save