|
|
|
@ -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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |