Browse Source

Merge pull request #937 from AvaloniaUI/fix-mouseover

Ported changes to Avalonia.Input from scenegraph.
pull/940/head
Steven Kirk 10 years ago
committed by GitHub
parent
commit
42400f52be
  1. 6
      src/Avalonia.Input/IInputElement.cs
  2. 125
      src/Avalonia.Input/MouseDevice.cs

6
src/Avalonia.Input/IInputElement.cs

@ -93,17 +93,17 @@ namespace Avalonia.Input
bool IsEnabledCore { get; } bool IsEnabledCore { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the control is focused. /// Gets a value indicating whether the control is focused.
/// </summary> /// </summary>
bool IsFocused { get; } bool IsFocused { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the control is considered for hit testing. /// Gets a value indicating whether the control is considered for hit testing.
/// </summary> /// </summary>
bool IsHitTestVisible { get; } bool IsHitTestVisible { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the pointer is currently over the control. /// Gets a value indicating whether the pointer is currently over the control.
/// </summary> /// </summary>
bool IsPointerOver { get; } bool IsPointerOver { get; }

125
src/Avalonia.Input/MouseDevice.cs

@ -20,7 +20,6 @@ namespace Avalonia.Input
private int _clickCount; private int _clickCount;
private Rect _lastClickRect; private Rect _lastClickRect;
private uint _lastClickTime; private uint _lastClickTime;
private readonly List<IInputElement> _pointerOvers = new List<IInputElement>();
/// <summary> /// <summary>
/// Intializes a new instance of <see cref="MouseDevice"/>. /// Intializes a new instance of <see cref="MouseDevice"/>.
@ -87,6 +86,8 @@ namespace Avalonia.Input
/// <returns>The mouse position in the control's coordinates.</returns> /// <returns>The mouse position in the control's coordinates.</returns>
public Point GetPosition(IVisual relativeTo) public Point GetPosition(IVisual relativeTo)
{ {
Contract.Requires<ArgumentNullException>(relativeTo != null);
Point p = default(Point); Point p = default(Point);
IVisual v = relativeTo; IVisual v = relativeTo;
IVisual root = null; IVisual root = null;
@ -103,6 +104,8 @@ namespace Avalonia.Input
private void ProcessRawEvent(RawMouseEventArgs e) private void ProcessRawEvent(RawMouseEventArgs e)
{ {
Contract.Requires<ArgumentNullException>(e != null);
var mouse = (IMouseDevice)e.Device; var mouse = (IMouseDevice)e.Device;
Position = e.Root.PointToScreen(e.Position); Position = e.Root.PointToScreen(e.Position);
@ -141,11 +144,17 @@ namespace Avalonia.Input
private void LeaveWindow(IMouseDevice device, IInputRoot root) private void LeaveWindow(IMouseDevice device, IInputRoot root)
{ {
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
ClearPointerOver(this, root); ClearPointerOver(this, root);
} }
private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers) private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
var hit = HitTest(root, p); var hit = HitTest(root, p);
if (hit != null) if (hit != null)
@ -187,6 +196,9 @@ namespace Avalonia.Input
private bool MouseMove(IMouseDevice device, IInputRoot root, Point p, InputModifiers inputModifiers) private bool MouseMove(IMouseDevice device, IInputRoot root, Point p, InputModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
IInputElement source; IInputElement source;
if (Captured == null) if (Captured == null)
@ -195,8 +207,7 @@ namespace Avalonia.Input
} }
else else
{ {
var elements = Captured.GetSelfAndVisualAncestors().OfType<IInputElement>().ToList(); SetPointerOver(this, root, Captured);
SetPointerOver(this, root, elements);
source = Captured; source = Captured;
} }
@ -208,12 +219,15 @@ namespace Avalonia.Input
InputModifiers = inputModifiers InputModifiers = inputModifiers
}; };
source.RaiseEvent(e); source?.RaiseEvent(e);
return e.Handled; return e.Handled;
} }
private bool MouseUp(IMouseDevice device, IInputRoot root, Point p, MouseButton button, InputModifiers inputModifiers) private bool MouseUp(IMouseDevice device, IInputRoot root, Point p, MouseButton button, InputModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
var hit = HitTest(root, p); var hit = HitTest(root, p);
if (hit != null) if (hit != null)
@ -237,6 +251,9 @@ namespace Avalonia.Input
private bool MouseWheel(IMouseDevice device, IInputRoot root, Point p, Vector delta, InputModifiers inputModifiers) private bool MouseWheel(IMouseDevice device, IInputRoot root, Point p, Vector delta, InputModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
var hit = HitTest(root, p); var hit = HitTest(root, p);
if (hit != null) if (hit != null)
@ -260,6 +277,8 @@ namespace Avalonia.Input
private IInteractive GetSource(IVisual hit) private IInteractive GetSource(IVisual hit)
{ {
Contract.Requires<ArgumentNullException>(hit != null);
return Captured ?? return Captured ??
(hit as IInteractive) ?? (hit as IInteractive) ??
hit.GetSelfAndVisualAncestors().OfType<IInteractive>().FirstOrDefault(); hit.GetSelfAndVisualAncestors().OfType<IInteractive>().FirstOrDefault();
@ -267,22 +286,28 @@ namespace Avalonia.Input
private IInputElement HitTest(IInputElement root, Point p) private IInputElement HitTest(IInputElement root, Point p)
{ {
Contract.Requires<ArgumentNullException>(root != null);
return Captured ?? root.InputHitTest(p); return Captured ?? root.InputHitTest(p);
} }
private void ClearPointerOver(IPointerDevice device, IInputRoot root) private void ClearPointerOver(IPointerDevice device, IInputRoot root)
{ {
foreach (var control in _pointerOvers.ToList()) Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
var element = root.PointerOverElement;
var e = new PointerEventArgs
{ {
PointerEventArgs e = new PointerEventArgs RoutedEvent = InputElement.PointerLeaveEvent,
{ Device = device,
RoutedEvent = InputElement.PointerLeaveEvent, };
Device = device,
Source = control,
};
_pointerOvers.Remove(control); while (element != null)
control.RaiseEvent(e); {
e.Source = element;
element.RaiseEvent(e);
element = (IInputElement)element.VisualParent;
} }
root.PointerOverElement = null; root.PointerOverElement = null;
@ -290,40 +315,66 @@ namespace Avalonia.Input
private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, Point p) private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, Point p)
{ {
var elements = root.GetInputElementsAt(p).ToList(); Contract.Requires<ArgumentNullException>(device != null);
return SetPointerOver(device, root, elements); Contract.Requires<ArgumentNullException>(root != null);
var element = root.InputHitTest(p);
if (element != root.PointerOverElement)
{
if (element != null)
{
SetPointerOver(device, root, element);
}
else
{
ClearPointerOver(device, root);
}
}
return element;
} }
private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, IList<IInputElement> elements) private void SetPointerOver(IPointerDevice device, IInputRoot root, IInputElement element)
{ {
foreach (var control in _pointerOvers.Except(elements).ToList()) Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
Contract.Requires<ArgumentNullException>(element != null);
IInputElement branch = null;
var e = new PointerEventArgs
{ {
PointerEventArgs e = new PointerEventArgs RoutedEvent = InputElement.PointerEnterEvent,
{ Device = device,
RoutedEvent = InputElement.PointerLeaveEvent, };
Device = device,
Source = control,
};
_pointerOvers.Remove(control); var el = element;
control.RaiseEvent(e);
}
foreach (var control in elements.Except(_pointerOvers)) while (el != null)
{ {
PointerEventArgs e = new PointerEventArgs if (el.IsPointerOver)
{ {
RoutedEvent = InputElement.PointerEnterEvent, branch = el;
Device = device, break;
Source = control, }
};
_pointerOvers.Add(control); e.Source = el;
control.RaiseEvent(e); el.RaiseEvent(e);
el = (IInputElement)el.VisualParent;
}
el = root.PointerOverElement;
e.RoutedEvent = InputElement.PointerLeaveEvent;
while (el != null && el != branch)
{
e.Source = el;
el.RaiseEvent(e);
el = (IInputElement)el.VisualParent;
} }
root.PointerOverElement = elements.FirstOrDefault() ?? root; root.PointerOverElement = element;
return root.PointerOverElement;
} }
} }
} }
Loading…
Cancel
Save