diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs index 581aaa2da2..6f14f054eb 100644 --- a/Perspex.Controls/Control.cs +++ b/Perspex.Controls/Control.cs @@ -28,7 +28,7 @@ namespace Perspex.Controls PerspexProperty.Register("BorderThickness"); public static readonly PerspexProperty ForegroundProperty = - PerspexProperty.Register("Foreground", new SolidColorBrush(0xff000000), true); + PerspexProperty.Register("Foreground", new SolidColorBrush(0xff000000), inherits: true); public static readonly PerspexProperty TemplatedParentProperty = PerspexProperty.Register("TemplatedParent", inherits: true); @@ -44,8 +44,9 @@ namespace Perspex.Controls static Control() { Control.AffectsMeasure(Control.IsVisibleProperty); - PseudoClass(Control.IsPointerOverProperty, ":pointerover"); - PseudoClass(Control.IsFocusedProperty, ":focus"); + PseudoClass(InputElement.IsEnabledCoreProperty, x => !x, ":disabled"); + PseudoClass(InputElement.IsFocusedProperty, ":focus"); + PseudoClass(InputElement.IsPointerOverProperty, ":pointerover"); } public Brush Background @@ -190,6 +191,8 @@ namespace Perspex.Controls protected override void OnAttachedToVisualTree(IRenderRoot root) { + base.OnAttachedToVisualTree(root); + IStyler styler = Locator.Current.GetService(); styler.ApplyStyles(this); } diff --git a/Perspex.Input/IInputElement.cs b/Perspex.Input/IInputElement.cs index f7e3c28133..1f54bf2c48 100644 --- a/Perspex.Input/IInputElement.cs +++ b/Perspex.Input/IInputElement.cs @@ -27,10 +27,16 @@ namespace Perspex.Input bool Focusable { get; } + bool IsEnabled { get; } + + bool IsEnabledCore { get; } + bool IsFocused { get; } bool IsPointerOver { get; } void Focus(); + + IInputElement InputHitTest(Point p); } } diff --git a/Perspex.Input/InputElement.cs b/Perspex.Input/InputElement.cs index e42ee69894..14934a8be9 100644 --- a/Perspex.Input/InputElement.cs +++ b/Perspex.Input/InputElement.cs @@ -7,14 +7,21 @@ namespace Perspex.Input { using System; + using System.Linq; using Perspex.Interactivity; - using Splat; + using Perspex.Rendering; 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", false); @@ -51,6 +58,11 @@ namespace Perspex.Input public static readonly RoutedEvent PointerWheelChangedEvent = RoutedEvent.Register("PointerWheelChanged", RoutingStrategy.Bubble); + static InputElement() + { + IsEnabledProperty.Changed.Subscribe(IsEnabledChanged); + } + public InputElement() { this.GotFocus += (_, e) => this.OnGotFocus(e); @@ -131,6 +143,12 @@ namespace Perspex.Input 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); } @@ -143,11 +161,35 @@ namespace Perspex.Input internal set { this.SetValue(IsPointerOverProperty, value); } } + bool IInputElement.IsEnabledCore + { + get { return this.IsEnabledCore; } + } + + protected bool IsEnabledCore + { + get { return this.GetValue(IsEnabledCoreProperty); } + set { this.SetValue(IsEnabledCoreProperty, value); } + } + + public IInputElement InputHitTest(Point p) + { + return this.GetVisualsAt(p) + .OfType() + .Where(x => x.IsEnabledCore) + .FirstOrDefault(); + } + public void Focus() { FocusManager.Instance.Focus(this); } + protected override void OnVisualParentChanged(Visual oldParent) + { + this.UpdateIsEnabledCore(); + } + protected virtual void OnGotFocus(RoutedEventArgs e) { this.IsFocused = e.OriginalSource == this; @@ -191,5 +233,32 @@ namespace Perspex.Input 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); + } + } } } diff --git a/Perspex.Input/InputManager.cs b/Perspex.Input/InputManager.cs index c0ea7aea18..dc86cf8016 100644 --- a/Perspex.Input/InputManager.cs +++ b/Perspex.Input/InputManager.cs @@ -30,7 +30,9 @@ namespace Perspex.Input public void SetPointerOver(IPointerDevice device, IVisual visual, Point p) { - IEnumerable hits = visual.GetVisualsAt(p).OfType(); + IEnumerable hits = visual.GetVisualsAt(p) + .OfType() + .Where(x => x.IsEnabledCore); foreach (var control in this.pointerOvers.Except(hits).ToList()) { diff --git a/Perspex.Input/MouseDevice.cs b/Perspex.Input/MouseDevice.cs index c3ea4cefdf..1a06ce1bf1 100644 --- a/Perspex.Input/MouseDevice.cs +++ b/Perspex.Input/MouseDevice.cs @@ -63,37 +63,35 @@ namespace Perspex.Input private void ProcessRawEvent(RawMouseEventArgs e) { + var mouse = (IMouseDevice)e.Device; + this.Position = e.Position; switch (e.Type) { case RawMouseEventType.Move: - this.MouseMove((IMouseDevice)e.Device, (IVisual)e.Root, e.Position); + this.MouseMove(mouse, e.Root, e.Position); break; case RawMouseEventType.LeftButtonDown: - this.MouseDown((IMouseDevice)e.Device, (IVisual)e.Root, e.Position); + this.MouseDown(mouse, e.Root, e.Position); break; case RawMouseEventType.LeftButtonUp: - this.MouseUp((IMouseDevice)e.Device, (IVisual)e.Root, e.Position); + this.MouseUp(mouse, e.Root, e.Position); break; case RawMouseEventType.Wheel: - this.MouseWheel( - (IMouseDevice)e.Device, - (IVisual)e.Root, - e.Position, - ((RawMouseWheelEventArgs)e).Delta); + this.MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta); break; } } - private void MouseMove(IMouseDevice device, IVisual visual, Point p) + private void MouseMove(IMouseDevice device, IInputElement root, Point p) { IInteractive source; if (this.Captured == null) { - this.InputManager.SetPointerOver(this, visual, p); - source = visual as IInteractive; + this.InputManager.SetPointerOver(this, root, p); + source = root as IInteractive; } else { @@ -120,9 +118,9 @@ namespace Perspex.Input } } - private void MouseDown(IMouseDevice device, IVisual visual, Point p) + private void MouseDown(IMouseDevice device, IInputElement root, Point p) { - IVisual hit = visual.GetVisualAt(p); + IVisual hit = root.InputHitTest(p); if (hit != null) { @@ -148,9 +146,9 @@ namespace Perspex.Input } } - private void MouseUp(IMouseDevice device, IVisual visual, Point p) + private void MouseUp(IMouseDevice device, IInputElement root, Point p) { - IVisual hit = visual.GetVisualAt(p); + IVisual hit = root.InputHitTest(p); if (hit != null) { @@ -169,9 +167,9 @@ namespace Perspex.Input } } - private void MouseWheel(IMouseDevice device, IVisual visual, Point p, Vector delta) + private void MouseWheel(IMouseDevice device, IInputElement root, Point p, Vector delta) { - IVisual hit = visual.GetVisualAt(p); + IVisual hit = root.InputHitTest(p); if (hit != null) { diff --git a/Perspex.Input/Raw/RawMouseEventArgs.cs b/Perspex.Input/Raw/RawMouseEventArgs.cs index 6c1b92323a..0b79c4e245 100644 --- a/Perspex.Input/Raw/RawMouseEventArgs.cs +++ b/Perspex.Input/Raw/RawMouseEventArgs.cs @@ -21,7 +21,7 @@ namespace Perspex.Input.Raw { public RawMouseEventArgs( IInputDevice device, - ILayoutRoot root, + IInputElement root, RawMouseEventType type, Point position) : base(device) @@ -34,8 +34,7 @@ namespace Perspex.Input.Raw this.Type = type; } - // TODO: This should probably be IInputRoot or something. - public ILayoutRoot Root { get; private set; } + public IInputElement Root { get; private set; } public Point Position { get; private set; } diff --git a/Perspex.Input/Raw/RawMouseWheelEventArgs.cs b/Perspex.Input/Raw/RawMouseWheelEventArgs.cs index a516160a73..70fb1871bc 100644 --- a/Perspex.Input/Raw/RawMouseWheelEventArgs.cs +++ b/Perspex.Input/Raw/RawMouseWheelEventArgs.cs @@ -13,7 +13,7 @@ namespace Perspex.Input.Raw { public RawMouseWheelEventArgs( IInputDevice device, - ILayoutRoot root, + IInputElement root, Point position, Vector delta) : base(device, root, RawMouseEventType.Wheel, position) diff --git a/Perspex.Themes.Default/ButtonStyle.cs b/Perspex.Themes.Default/ButtonStyle.cs index b91065d3cc..925d9c1ae6 100644 --- a/Perspex.Themes.Default/ButtonStyle.cs +++ b/Perspex.Themes.Default/ButtonStyle.cs @@ -60,6 +60,13 @@ namespace Perspex.Themes.Default new Setter(Button.BorderBrushProperty, new SolidColorBrush(0xffff628b)), }, }, + new Style(x => x.OfType