Browse Source

Merge pull request #937 from AvaloniaUI/fix-mouseover

Ported changes to Avalonia.Input from scenegraph.
pull/940/head
Steven Kirk 9 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; }
/// <summary>
/// Gets or sets a value indicating whether the control is focused.
/// Gets a value indicating whether the control is focused.
/// </summary>
bool IsFocused { get; }
/// <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>
bool IsHitTestVisible { get; }
/// <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>
bool IsPointerOver { get; }

125
src/Avalonia.Input/MouseDevice.cs

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