// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Input { using System; using System.Linq; using Perspex.Interactivity; using Perspex.Rendering; using Perspex.VisualTree; public class InputElement : Interactive, IInputElement { public static readonly PerspexProperty FocusableProperty = PerspexProperty.Register("Focusable"); public static readonly PerspexProperty IsEnabledProperty = PerspexProperty.Register("IsEnabled", true); public static readonly PerspexProperty IsEnabledCoreProperty = PerspexProperty.Register("IsEnabledCore", true); public static readonly PerspexProperty IsFocusedProperty = PerspexProperty.Register("IsFocused"); public static readonly PerspexProperty IsHitTestVisibleProperty = PerspexProperty.Register("IsHitTestVisible", true); public static readonly PerspexProperty IsPointerOverProperty = PerspexProperty.Register("IsPointerOver"); public static readonly PerspexProperty IsTabFocusedProperty = PerspexProperty.Register("IsTabFocused"); public static readonly RoutedEvent GotFocusEvent = RoutedEvent.Register("GotFocus", RoutingStrategies.Bubble); public static readonly RoutedEvent LostFocusEvent = RoutedEvent.Register("LostFocus", RoutingStrategies.Bubble); public static readonly RoutedEvent KeyDownEvent = RoutedEvent.Register( "KeyDown", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); public static readonly RoutedEvent KeyUpEvent = RoutedEvent.Register( "KeyUp", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); public static readonly RoutedEvent PointerEnterEvent = RoutedEvent.Register("PointerEnter", RoutingStrategies.Direct); public static readonly RoutedEvent PointerLeaveEvent = RoutedEvent.Register("PointerLeave", RoutingStrategies.Direct); public static readonly RoutedEvent PointerMovedEvent = RoutedEvent.Register( "PointerMove", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); public static readonly RoutedEvent PointerPressedEvent = RoutedEvent.Register( "PointerPressed", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); public static readonly RoutedEvent PointerReleasedEvent = RoutedEvent.Register( "PointerReleased", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); public static readonly RoutedEvent PointerWheelChangedEvent = RoutedEvent.Register( "PointerWheelChanged", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); static InputElement() { IsEnabledProperty.Changed.Subscribe(IsEnabledChanged); GotFocusEvent.AddClassHandler(x => x.OnGotFocus); LostFocusEvent.AddClassHandler(x => x.OnLostFocus); KeyDownEvent.AddClassHandler(x => x.OnKeyDown); KeyUpEvent.AddClassHandler(x => x.OnKeyUp); PointerEnterEvent.AddClassHandler(x => x.OnPointerEnter); PointerLeaveEvent.AddClassHandler(x => x.OnPointerLeave); PointerMovedEvent.AddClassHandler(x => x.OnPointerMoved); PointerPressedEvent.AddClassHandler(x => x.OnPointerPressed); PointerReleasedEvent.AddClassHandler(x => x.OnPointerReleased); PointerWheelChangedEvent.AddClassHandler(x => x.OnPointerWheelChanged); } public event EventHandler GotFocus { add { this.AddHandler(GotFocusEvent, value); } remove { this.RemoveHandler(GotFocusEvent, value); } } public event EventHandler LostFocus { add { this.AddHandler(LostFocusEvent, value); } remove { this.RemoveHandler(LostFocusEvent, value); } } public event EventHandler KeyDown { add { this.AddHandler(KeyDownEvent, value); } remove { this.RemoveHandler(KeyDownEvent, value); } } public event EventHandler KeyUp { add { this.AddHandler(KeyUpEvent, value); } remove { this.RemoveHandler(KeyUpEvent, value); } } public event EventHandler PointerEnter { add { this.AddHandler(PointerEnterEvent, value); } remove { this.RemoveHandler(PointerEnterEvent, value); } } public event EventHandler PointerLeave { add { this.AddHandler(PointerLeaveEvent, value); } remove { this.RemoveHandler(PointerLeaveEvent, value); } } public event EventHandler PointerMoved { add { this.AddHandler(PointerMovedEvent, value); } remove { this.RemoveHandler(PointerMovedEvent, value); } } public event EventHandler PointerPressed { add { this.AddHandler(PointerPressedEvent, value); } remove { this.RemoveHandler(PointerPressedEvent, value); } } public event EventHandler PointerReleased { add { this.AddHandler(PointerReleasedEvent, value); } remove { this.RemoveHandler(PointerReleasedEvent, value); } } public event EventHandler PointerWheelChanged { add { this.AddHandler(PointerWheelChangedEvent, value); } remove { this.RemoveHandler(PointerWheelChangedEvent, value); } } public bool Focusable { get { return this.GetValue(FocusableProperty); } set { this.SetValue(FocusableProperty, value); } } public bool IsEnabled { get { return this.GetValue(IsEnabledProperty); } set { this.SetValue(IsEnabledProperty, value); } } public bool IsFocused { get { return this.GetValue(IsFocusedProperty); } private set { this.SetValue(IsFocusedProperty, value); } } public bool IsHitTestVisible { get { return this.GetValue(IsHitTestVisibleProperty); } set { this.SetValue(IsHitTestVisibleProperty, value); } } public bool IsPointerOver { get { return this.GetValue(IsPointerOverProperty); } internal set { this.SetValue(IsPointerOverProperty, value); } } bool IInputElement.IsEnabledCore { get { return this.IsEnabledCore; } } bool IInputElement.IsTabFocused { get { return this.GetValue(IsTabFocusedProperty); } } protected bool IsEnabledCore { get { return this.GetValue(IsEnabledCoreProperty); } set { this.SetValue(IsEnabledCoreProperty, value); } } public IInputElement InputHitTest(Point p) { return this.GetInputElementsAt(p).FirstOrDefault(); } public void Focus() { FocusManager.Instance.Focus(this); } protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot) { base.OnDetachedFromVisualTree(oldRoot); if (this.IsFocused) { FocusManager.Instance.Focus(null); } } protected override void OnVisualParentChanged(Visual oldParent) { this.UpdateIsEnabledCore(); } protected virtual void OnGotFocus(GotFocusEventArgs e) { this.IsFocused = e.OriginalSource == this; this.SetValue(IsTabFocusedProperty, e.KeyboardNavigated); } protected virtual void OnLostFocus(RoutedEventArgs e) { this.IsFocused = false; this.SetValue(IsTabFocusedProperty, false); } protected virtual void OnKeyDown(KeyEventArgs e) { } protected virtual void OnKeyUp(KeyEventArgs e) { } protected virtual void OnPointerEnter(PointerEventArgs e) { this.IsPointerOver = true; } protected virtual void OnPointerLeave(PointerEventArgs e) { this.IsPointerOver = false; } protected virtual void OnPointerMoved(PointerEventArgs e) { } protected virtual void OnPointerPressed(PointerPressEventArgs e) { } protected virtual void OnPointerReleased(PointerEventArgs e) { } protected virtual void OnPointerWheelChanged(PointerWheelEventArgs e) { } private static void IsEnabledChanged(PerspexPropertyChangedEventArgs e) { ((InputElement)e.Sender).UpdateIsEnabledCore(); } private void UpdateIsEnabledCore() { this.UpdateIsEnabledCore(this.GetVisualParent()); } private void UpdateIsEnabledCore(InputElement parent) { if (parent != null) { this.IsEnabledCore = this.IsEnabled && parent.IsEnabledCore; } else { this.IsEnabledCore = this.IsEnabled; } foreach (var child in this.GetVisualChildren().OfType()) { child.UpdateIsEnabledCore(this); } } } }