Browse Source

Initial implementation of IsKeyboardFocusWithin

pull/4974/head
Dan Walmsley 6 years ago
parent
commit
98c2b0f9e0
  1. 4
      src/Avalonia.Input/ApiCompatBaseline.txt
  2. 5
      src/Avalonia.Input/IInputElement.cs
  3. 24
      src/Avalonia.Input/InputElement.cs
  4. 71
      src/Avalonia.Input/KeyboardDevice.cs

4
src/Avalonia.Input/ApiCompatBaseline.txt

@ -0,0 +1,4 @@
Compat issues with assembly Avalonia.Input:
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Input.IInputElement.IsKeyboardFocusWithin' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Input.IInputElement.IsKeyboardFocusWithin.get()' is present in the implementation but not in the contract.
Total Issues: 2

5
src/Avalonia.Input/IInputElement.cs

@ -89,6 +89,11 @@ namespace Avalonia.Input
/// <see cref="IsEnabled"/> value of this control and its parent controls.
/// </remarks>
bool IsEffectivelyEnabled { get; }
/// <summary>
/// Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements.
/// </summary>
bool IsKeyboardFocusWithin { get; }
/// <summary>
/// Gets a value indicating whether the control is focused.

24
src/Avalonia.Input/InputElement.cs

@ -42,6 +42,14 @@ namespace Avalonia.Input
public static readonly StyledProperty<Cursor?> CursorProperty =
AvaloniaProperty.Register<InputElement, Cursor?>(nameof(Cursor), null, true);
/// <summary>
/// Defines the <see cref="IsKeyboardFocusWithin"/> property.
/// </summary>
public static readonly DirectProperty<InputElement, bool> IsKeyboardFocusWithinProperty =
AvaloniaProperty.RegisterDirect<InputElement, bool>(
nameof(IsKeyboardFocusWithin),
o => o.IsKeyboardFocusWithin);
/// <summary>
/// Defines the <see cref="IsFocused"/> property.
/// </summary>
@ -160,6 +168,7 @@ namespace Avalonia.Input
private bool _isEffectivelyEnabled = true;
private bool _isFocused;
private bool _isKeyboardFocusWithin;
private bool _isFocusVisible;
private bool _isPointerOver;
private GestureRecognizerCollection? _gestureRecognizers;
@ -343,6 +352,15 @@ namespace Avalonia.Input
get { return GetValue(CursorProperty); }
set { SetValue(CursorProperty, value); }
}
/// <summary>
/// Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements.
/// </summary>
public bool IsKeyboardFocusWithin
{
get => _isKeyboardFocusWithin;
internal set => SetAndRaise(IsKeyboardFocusWithinProperty, ref _isKeyboardFocusWithin, value);
}
/// <summary>
/// Gets a value indicating whether the control is focused.
@ -423,7 +441,7 @@ namespace Avalonia.Input
base.OnAttachedToVisualTreeCore(e);
UpdateIsEffectivelyEnabled();
}
/// <summary>
/// Called before the <see cref="GotFocus"/> event occurs.
/// </summary>
@ -544,6 +562,10 @@ namespace Avalonia.Input
{
UpdatePseudoClasses(null, change.NewValue.GetValueOrDefault<bool>());
}
else if (change.Property == IsKeyboardFocusWithinProperty)
{
PseudoClasses.Set(":focus-within", _isKeyboardFocusWithin);
}
}
/// <summary>

71
src/Avalonia.Input/KeyboardDevice.cs

@ -31,6 +31,74 @@ namespace Avalonia.Input
RaisePropertyChanged();
}
}
private void ClearFocusWithin(IInputElement element, bool clearRoot)
{
foreach (IInputElement el in element.VisualChildren)
{
if (el.IsKeyboardFocusWithin)
{
ClearFocusWithin(el, true);
break;
}
}
if(clearRoot)
{
if (element is InputElement ie)
{
ie.IsKeyboardFocusWithin = false;
}
}
}
private void SetIsFocusWithin(InputElement oldElement, InputElement newElement)
{
InputElement? branch = null;
InputElement el = newElement;
while (el != null)
{
if (el.IsKeyboardFocusWithin)
{
branch = el;
break;
}
if ((el as IInputElement).VisualParent is InputElement ie)
{
el = ie;
}
else
{
break;
}
}
el = oldElement;
if (el != null && branch != null)
{
ClearFocusWithin(branch, false);
}
el = newElement;
while (el != null && el != branch)
{
el.IsKeyboardFocusWithin = true;
if ((el as IInputElement).VisualParent is InputElement ie)
{
el = ie;
}
else
{
break;
}
}
}
public void SetFocusedElement(
IInputElement? element,
@ -40,6 +108,9 @@ namespace Avalonia.Input
if (element != FocusedElement)
{
var interactive = FocusedElement as IInteractive;
SetIsFocusWithin(FocusedElement as InputElement, element as InputElement);
FocusedElement = element;
interactive?.RaiseEvent(new RoutedEventArgs

Loading…
Cancel
Save