Browse Source

Show keyboard focus adorner.

pull/39/head
Steven Kirk 12 years ago
parent
commit
6fa126f827
  1. 5
      Perspex.Base/Collections/PerspexList.cs
  2. 39
      Perspex.Controls/Control.cs
  3. 2
      Perspex.Controls/Primitives/AdornerLayer.cs
  4. 2
      Perspex.Controls/TextBox.cs
  5. 4
      Perspex.Diagnostics/DevTools.cs
  6. 8
      Perspex.Input/FocusManager.cs
  7. 19
      Perspex.Input/GotFocusEventArgs.cs
  8. 9
      Perspex.Input/IFocusManager.cs
  9. 2
      Perspex.Input/IInputElement.cs
  10. 18
      Perspex.Input/InputElement.cs
  11. 4
      Perspex.Input/KeyboardNavigation.cs
  12. 1
      Perspex.Input/Perspex.Input.csproj

5
Perspex.Base/Collections/PerspexList.cs

@ -37,6 +37,11 @@ namespace Perspex.Collections
this.inner = new List<T>(items); this.inner = new List<T>(items);
} }
public PerspexList(params T[] items)
{
this.inner = new List<T>(items);
}
public event NotifyCollectionChangedEventHandler CollectionChanged; public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;

39
Perspex.Controls/Control.cs

@ -11,6 +11,8 @@ namespace Perspex.Controls
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using Perspex.Collections; using Perspex.Collections;
using Perspex.Controls.Primitives;
using Perspex.Controls.Shapes;
using Perspex.Input; using Perspex.Input;
using Perspex.Interactivity; using Perspex.Interactivity;
using Perspex.Media; using Perspex.Media;
@ -41,6 +43,8 @@ namespace Perspex.Controls
private DataTemplates dataTemplates; private DataTemplates dataTemplates;
private Rectangle focusAdorner;
private string id; private string id;
private Styles styles; private Styles styles;
@ -185,6 +189,41 @@ namespace Perspex.Controls
this.RaiseEvent(ev); this.RaiseEvent(ev);
} }
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
if (this.IsFocused && e.KeyboardNavigated)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(this);
if (adornerLayer != null)
{
this.focusAdorner = new Rectangle
{
Stroke = Brushes.Black,
StrokeThickness = 1,
StrokeDashArray = new PerspexList<double>(1, 2),
Margin = new Thickness(3),
};
AdornerLayer.SetAdornedElement(this.focusAdorner, this);
adornerLayer.Children.Add(this.focusAdorner);
}
}
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
if (this.focusAdorner != null)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(this);
adornerLayer.Children.Remove(this.focusAdorner);
this.focusAdorner = null;
}
}
protected static void PseudoClass(PerspexProperty<bool> property, string className) protected static void PseudoClass(PerspexProperty<bool> property, string className)
{ {
PseudoClass(property, x => x, className); PseudoClass(property, x => x, className);

2
Perspex.Controls/Primitives/AdornerLayer.cs

@ -51,7 +51,7 @@ namespace Perspex.Controls.Primitives
{ {
var transform = adorned.TransformToVisual(parent); var transform = adorned.TransformToVisual(parent);
var position = new Point(0, 0) * transform; var position = new Point(0, 0) * transform;
child.Arrange(new Rect(position, child.DesiredSize.Value)); child.Arrange(new Rect(position, adorned.Bounds.Size));
} }
else else
{ {

2
Perspex.Controls/TextBox.cs

@ -114,7 +114,7 @@ namespace Perspex.Controls
this.presenter = this.GetTemplateChild<TextPresenter>("textPresenter"); this.presenter = this.GetTemplateChild<TextPresenter>("textPresenter");
} }
protected override void OnGotFocus(RoutedEventArgs e) protected override void OnGotFocus(GotFocusEventArgs e)
{ {
base.OnGotFocus(e); base.OnGotFocus(e);
this.presenter.ShowCaret(); this.presenter.ShowCaret();

4
Perspex.Diagnostics/DevTools.cs

@ -216,13 +216,9 @@ namespace Perspex.Diagnostics
if (layer != null) if (layer != null)
{ {
var size = node.Control.GetObservable(Visual.BoundsProperty).Select(x => x.Size);
this.adorner = new Rectangle this.adorner = new Rectangle
{ {
Fill = new SolidColorBrush(0x80a0c5e8), Fill = new SolidColorBrush(0x80a0c5e8),
[!Layoutable.WidthProperty] = size.Select(x => (object)x.Width),
[!Layoutable.HeightProperty] = size.Select(x => (object)x.Height),
[AdornerLayer.AdornedElementProperty] = node.Control, [AdornerLayer.AdornedElementProperty] = node.Control,
}; };

8
Perspex.Input/FocusManager.cs

@ -39,7 +39,10 @@ namespace Perspex.Input
/// Focuses a control. /// Focuses a control.
/// </summary> /// </summary>
/// <param name="control">The control to focus.</param> /// <param name="control">The control to focus.</param>
public void Focus(IInputElement control) /// <param name="keyboardNavigated">
/// Whether the control was focused by a keypress (e.g. the Tab key).
/// </param>
public void Focus(IInputElement control, bool keyboardNavigated = false)
{ {
Contract.Requires<ArgumentNullException>(control != null); Contract.Requires<ArgumentNullException>(control != null);
@ -74,11 +77,12 @@ namespace Perspex.Input
if (next != null) if (next != null)
{ {
next.RaiseEvent(new RoutedEventArgs next.RaiseEvent(new GotFocusEventArgs
{ {
RoutedEvent = InputElement.GotFocusEvent, RoutedEvent = InputElement.GotFocusEvent,
Source = next, Source = next,
OriginalSource = next, OriginalSource = next,
KeyboardNavigated = keyboardNavigated,
}); });
} }
} }

19
Perspex.Input/GotFocusEventArgs.cs

@ -0,0 +1,19 @@
// -----------------------------------------------------------------------
// <copyright file="GotFocusEventArgs.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Input
{
using Perspex.Interactivity;
public class GotFocusEventArgs : RoutedEventArgs
{
/// <summary>
/// Gets or sets a value indicating whether the control was focused by a keypress (e.g.
/// the Tab key).
/// </summary>
public bool KeyboardNavigated { get; set; }
}
}

9
Perspex.Input/IFocusManager.cs

@ -18,7 +18,14 @@ namespace Perspex.Input
IFocusScope Scope { get; } IFocusScope Scope { get; }
void Focus(IInputElement focusable); /// <summary>
/// Focuses a control.
/// </summary>
/// <param name="control">The control to focus.</param>
/// <param name="keyboardNavigated">
/// Whether the control was focused by a keypress (e.g. the Tab key).
/// </param>
void Focus(IInputElement focusable, bool keyboardNavigated = false);
/// <summary> /// <summary>
/// Notifies the focus manager of a change in focus scope. /// Notifies the focus manager of a change in focus scope.

2
Perspex.Input/IInputElement.cs

@ -37,6 +37,8 @@ namespace Perspex.Input
bool IsPointerOver { get; } bool IsPointerOver { get; }
bool IsTabFocused { get; }
void Focus(); void Focus();
IInputElement InputHitTest(Point p); IInputElement InputHitTest(Point p);

18
Perspex.Input/InputElement.cs

@ -23,7 +23,7 @@ namespace Perspex.Input
PerspexProperty.Register<InputElement, bool>("IsEnabledCore", true); PerspexProperty.Register<InputElement, bool>("IsEnabledCore", true);
public static readonly PerspexProperty<bool> IsFocusedProperty = public static readonly PerspexProperty<bool> IsFocusedProperty =
PerspexProperty.Register<InputElement, bool>("IsFocused", false); PerspexProperty.Register<InputElement, bool>("IsFocused");
public static readonly PerspexProperty<bool> IsHitTestVisibleProperty = public static readonly PerspexProperty<bool> IsHitTestVisibleProperty =
PerspexProperty.Register<InputElement, bool>("IsHitTestVisible", true); PerspexProperty.Register<InputElement, bool>("IsHitTestVisible", true);
@ -31,8 +31,11 @@ namespace Perspex.Input
public static readonly PerspexProperty<bool> IsPointerOverProperty = public static readonly PerspexProperty<bool> IsPointerOverProperty =
PerspexProperty.Register<InputElement, bool>("IsPointerOver"); PerspexProperty.Register<InputElement, bool>("IsPointerOver");
public static readonly RoutedEvent<RoutedEventArgs> GotFocusEvent = public static readonly PerspexProperty<bool> IsTabFocusedProperty =
RoutedEvent.Register<InputElement, RoutedEventArgs>("GotFocus", RoutingStrategies.Bubble); PerspexProperty.Register<InputElement, bool>("IsTabFocused");
public static readonly RoutedEvent<GotFocusEventArgs> GotFocusEvent =
RoutedEvent.Register<InputElement, GotFocusEventArgs>("GotFocus", RoutingStrategies.Bubble);
public static readonly RoutedEvent<RoutedEventArgs> LostFocusEvent = public static readonly RoutedEvent<RoutedEventArgs> LostFocusEvent =
RoutedEvent.Register<InputElement, RoutedEventArgs>("LostFocus", RoutingStrategies.Bubble); RoutedEvent.Register<InputElement, RoutedEventArgs>("LostFocus", RoutingStrategies.Bubble);
@ -172,6 +175,11 @@ namespace Perspex.Input
get { return this.IsEnabledCore; } get { return this.IsEnabledCore; }
} }
bool IInputElement.IsTabFocused
{
get { return this.GetValue(IsTabFocusedProperty); }
}
protected bool IsEnabledCore protected bool IsEnabledCore
{ {
get { return this.GetValue(IsEnabledCoreProperty); } get { return this.GetValue(IsEnabledCoreProperty); }
@ -193,14 +201,16 @@ namespace Perspex.Input
this.UpdateIsEnabledCore(); this.UpdateIsEnabledCore();
} }
protected virtual void OnGotFocus(RoutedEventArgs e) protected virtual void OnGotFocus(GotFocusEventArgs e)
{ {
this.IsFocused = e.OriginalSource == this; this.IsFocused = e.OriginalSource == this;
this.SetValue(IsTabFocusedProperty, e.KeyboardNavigated);
} }
protected virtual void OnLostFocus(RoutedEventArgs e) protected virtual void OnLostFocus(RoutedEventArgs e)
{ {
this.IsFocused = false; this.IsFocused = false;
this.SetValue(IsTabFocusedProperty, false);
} }
protected virtual void OnKeyDown(KeyEventArgs e) protected virtual void OnKeyDown(KeyEventArgs e)

4
Perspex.Input/KeyboardNavigation.cs

@ -26,7 +26,7 @@ namespace Perspex.Input
if (next != null) if (next != null)
{ {
FocusManager.Instance.Focus(next); FocusManager.Instance.Focus(next, true);
} }
} }
@ -42,7 +42,7 @@ namespace Perspex.Input
if (next != null) if (next != null)
{ {
FocusManager.Instance.Focus(next); FocusManager.Instance.Focus(next, true);
} }
} }
} }

1
Perspex.Input/Perspex.Input.csproj

@ -74,6 +74,7 @@
<Compile Include="Key.cs" /> <Compile Include="Key.cs" />
<Compile Include="KeyboardDevice.cs" /> <Compile Include="KeyboardDevice.cs" />
<Compile Include="KeyboardNavigation.cs" /> <Compile Include="KeyboardNavigation.cs" />
<Compile Include="GotFocusEventArgs.cs" />
<Compile Include="Platform\IPlatformSettings.cs" /> <Compile Include="Platform\IPlatformSettings.cs" />
<Compile Include="PointerPressEventArgs.cs" /> <Compile Include="PointerPressEventArgs.cs" />
<Compile Include="PointerWheelEventArgs.cs" /> <Compile Include="PointerWheelEventArgs.cs" />

Loading…
Cancel
Save