Browse Source

Merge remote-tracking branch 'origin/master' into render-inside-win-ui-comp-tree

pull/4346/head
Dan Walmsley 6 years ago
parent
commit
d1039b4cc1
  1. 13
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  2. 7
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  3. 2
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  4. 20
      src/Avalonia.Input/MouseDevice.cs
  5. 4
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  6. 14
      src/Avalonia.Visuals/Media/Drawing.cs
  7. 4
      src/Avalonia.Visuals/Media/Geometry.cs
  8. 44
      src/Avalonia.Visuals/Media/GeometryDrawing.cs
  9. 84
      src/Avalonia.X11/XI2Manager.cs
  10. 43
      src/Avalonia.X11/XIStructs.cs

13
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -340,8 +340,6 @@ namespace Avalonia.Controls
if (OwningGrid != null && OwningGrid.ColumnHeaders != null)
{
args.Pointer.Capture(this);
_dragMode = DragMode.MouseDown;
_frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth();
_lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition);
@ -413,8 +411,9 @@ namespace Avalonia.Controls
}
//TODO DragEvents
internal void OnMouseMove(ref bool handled, Point mousePosition, Point mousePositionHeaders)
internal void OnMouseMove(PointerEventArgs args, Point mousePosition, Point mousePositionHeaders)
{
var handled = args.Handled;
if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null)
{
return;
@ -438,7 +437,10 @@ namespace Avalonia.Controls
}
_lastMousePositionHeaders = mousePositionHeaders;
if (args.Pointer.Captured != this)
args.Pointer.Capture(this);
SetDragCursor(mousePosition);
}
@ -506,8 +508,7 @@ namespace Avalonia.Controls
Point mousePosition = e.GetPosition(this);
Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders);
bool handled = false;
OnMouseMove(ref handled, mousePosition, mousePositionHeaders);
OnMouseMove(e, mousePosition, mousePositionHeaders);
}
/// <summary>

7
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@ -512,6 +512,13 @@ namespace Avalonia.Controls.Presenters
var generator = Owner.ItemContainerGenerator;
var newOffset = -1.0;
//better not trigger any container generation/recycle while or layout stuff
//before panel is attached/visible
if (!panel.IsAttachedToVisualTree)
{
return null;
}
if (!panel.IsMeasureValid && panel.PreviousMeasure.HasValue)
{
//before any kind of scrolling we need to make sure panel measure is valid

2
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -67,8 +67,6 @@ namespace Avalonia.Controls.Primitives
{
get
{
if (IsPopup)
return null;
var rv = FindLayer<LightDismissOverlayLayer>();
if (rv == null)
{

20
src/Avalonia.Input/MouseDevice.cs

@ -19,6 +19,7 @@ namespace Avalonia.Input
private readonly Pointer _pointer;
private bool _disposed;
private PixelPoint? _position;
public MouseDevice(Pointer? pointer = null)
{
@ -39,10 +40,11 @@ namespace Avalonia.Input
/// <summary>
/// Gets the mouse position, in screen coordinates.
/// </summary>
[Obsolete("Use events instead")]
public PixelPoint Position
{
get;
protected set;
get => _position ?? new PixelPoint(-1, -1);
protected set => _position = value;
}
/// <summary>
@ -91,7 +93,16 @@ namespace Avalonia.Input
public void SceneInvalidated(IInputRoot root, Rect rect)
{
var clientPoint = root.PointToClient(Position);
// Pointer is outside of the target area
if (_position == null )
{
if (root.PointerOverElement != null)
ClearPointerOver(this, 0, root, PointerPointProperties.None, KeyModifiers.None);
return;
}
var clientPoint = root.PointToClient(_position.Value);
if (rect.Contains(clientPoint))
{
@ -132,7 +143,7 @@ namespace Avalonia.Input
if(mouse._disposed)
return;
Position = e.Root.PointToScreen(e.Position);
_position = e.Root.PointToScreen(e.Position);
var props = CreateProperties(e);
var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers);
switch (e.Type)
@ -176,6 +187,7 @@ namespace Avalonia.Input
device = device ?? throw new ArgumentNullException(nameof(device));
root = root ?? throw new ArgumentNullException(nameof(root));
_position = null;
ClearPointerOver(this, timestamp, root, properties, inputModifiers);
}

4
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -2,6 +2,8 @@ Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.Geometry.GetRenderBounds(Avalonia.Media.Pen)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Boolean Avalonia.Media.Geometry.StrokeContains(Avalonia.Media.Pen, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
@ -34,4 +36,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalon
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public Avalonia.Utilities.IRef<Avalonia.Platform.IRenderTargetBitmapImpl> Avalonia.Rendering.RenderLayer.Bitmap.get()' does not exist in the implementation but it does exist in the contract.
Total Issues: 35
Total Issues: 37

14
src/Avalonia.Visuals/Media/Drawing.cs

@ -1,11 +1,19 @@
using Avalonia.Platform;
namespace Avalonia.Media
namespace Avalonia.Media
{
/// <summary>
/// Abstract class that describes a 2-D drawing.
/// </summary>
public abstract class Drawing : AvaloniaObject
{
/// <summary>
/// Draws this drawing to the given <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public abstract void Draw(DrawingContext context);
/// <summary>
/// Gets the drawing's bounding rectangle.
/// </summary>
public abstract Rect GetBounds();
}
}

4
src/Avalonia.Visuals/Media/Geometry.cs

@ -84,7 +84,7 @@ namespace Avalonia.Media
/// </summary>
/// <param name="pen">The stroke thickness.</param>
/// <returns>The bounding rectangle.</returns>
public Rect GetRenderBounds(Pen pen) => PlatformImpl?.GetRenderBounds(pen) ?? Rect.Empty;
public Rect GetRenderBounds(IPen pen) => PlatformImpl?.GetRenderBounds(pen) ?? Rect.Empty;
/// <summary>
/// Indicates whether the geometry's fill contains the specified point.
@ -102,7 +102,7 @@ namespace Avalonia.Media
/// <param name="pen">The pen to use.</param>
/// <param name="point">The point.</param>
/// <returns><c>true</c> if the geometry contains the point; otherwise, <c>false</c>.</returns>
public bool StrokeContains(Pen pen, Point point)
public bool StrokeContains(IPen pen, Point point)
{
return PlatformImpl?.StrokeContains(pen, point) == true;
}

44
src/Avalonia.Visuals/Media/GeometryDrawing.cs

@ -1,12 +1,38 @@
using Avalonia.Metadata;
using Avalonia.Media.Immutable;
using Avalonia.Metadata;
namespace Avalonia.Media
{
/// <summary>
/// Represents a drawing operation that combines
/// a geometry with and brush and/or pen to produce rendered content.
/// </summary>
public class GeometryDrawing : Drawing
{
// Adding the Pen's stroke thickness here could yield wrong results due to transforms.
private static readonly IPen s_boundsPen = new ImmutablePen(Colors.Black.ToUint32(), 0);
/// <summary>
/// Defines the <see cref="Geometry"/> property.
/// </summary>
public static readonly StyledProperty<Geometry> GeometryProperty =
AvaloniaProperty.Register<GeometryDrawing, Geometry>(nameof(Geometry));
/// <summary>
/// Defines the <see cref="Brush"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
/// <summary>
/// Defines the <see cref="Pen"/> property.
/// </summary>
public static readonly StyledProperty<Pen> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen));
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.Geometry"/> that describes the shape of this <see cref="GeometryDrawing"/>.
/// </summary>
[Content]
public Geometry Geometry
{
@ -14,18 +40,18 @@ namespace Avalonia.Media
set => SetValue(GeometryProperty, value);
}
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.IBrush"/> used to fill the interior of the shape described by this <see cref="GeometryDrawing"/>.
/// </summary>
public IBrush Brush
{
get => GetValue(BrushProperty);
set => SetValue(BrushProperty, value);
}
public static readonly StyledProperty<Pen> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen));
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.IPen"/> used to stroke this <see cref="GeometryDrawing"/>.
/// </summary>
public IPen Pen
{
get => GetValue(PenProperty);
@ -42,9 +68,7 @@ namespace Avalonia.Media
public override Rect GetBounds()
{
// adding the Pen's stroke thickness here could yield wrong results due to transforms
var pen = new Pen(Brushes.Black, 0);
return Geometry?.GetRenderBounds(pen) ?? new Rect();
return Geometry?.GetRenderBounds(s_boundsPen) ?? Rect.Empty;
}
}
}

84
src/Avalonia.X11/XI2Manager.cs

@ -13,7 +13,10 @@ namespace Avalonia.X11
{
XiEventType.XI_Motion,
XiEventType.XI_ButtonPress,
XiEventType.XI_ButtonRelease
XiEventType.XI_ButtonRelease,
XiEventType.XI_Leave,
XiEventType.XI_Enter,
};
private static readonly XiEventType[] MultiTouchEventTypes = new XiEventType[]
@ -162,7 +165,9 @@ namespace Avalonia.X11
| XEventMask.Button4MotionMask
| XEventMask.Button5MotionMask
| XEventMask.ButtonPressMask
| XEventMask.ButtonReleaseMask;
| XEventMask.ButtonReleaseMask
| XEventMask.LeaveWindowMask
| XEventMask.EnterWindowMask;
}
public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid);
@ -175,14 +180,39 @@ namespace Avalonia.X11
_pointerDevice.Update(changed->Classes, changed->NumClasses);
}
if ((xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion)
|| (xev->evtype>=XiEventType.XI_TouchBegin&&xev->evtype<=XiEventType.XI_TouchEnd))
|| (xev->evtype >= XiEventType.XI_TouchBegin && xev->evtype <= XiEventType.XI_TouchEnd))
{
var dev = (XIDeviceEvent*)xev;
if (_clients.TryGetValue(dev->EventWindow, out var client))
OnDeviceEvent(client, new ParsedDeviceEvent(dev));
}
if (xev->evtype == XiEventType.XI_Leave || xev->evtype == XiEventType.XI_Enter)
{
var rev = (XIEnterLeaveEvent*)xev;
if (_clients.TryGetValue(rev->EventWindow, out var client))
OnEnterLeaveEvent(client, ref *rev);
}
}
void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
{
if (ev.evtype == XiEventType.XI_Leave)
{
var buttons = ParsedDeviceEvent.ParseButtonState(ev.buttons.MaskLen, ev.buttons.Mask);
var detail = ev.detail;
if ((detail == XiEnterLeaveDetail.XINotifyNonlinearVirtual ||
detail == XiEnterLeaveDetail.XINotifyNonlinear ||
detail == XiEnterLeaveDetail.XINotifyVirtual)
&& buttons == default)
{
client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, (ulong)ev.time.ToInt64(),
client.InputRoot,
RawPointerEventType.LeaveWindow, new Point(ev.event_x, ev.event_y), buttons));
}
}
}
void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
@ -284,6 +314,29 @@ namespace Avalonia.X11
public int Detail { get; set; }
public bool Emulated { get; set; }
public Dictionary<int, double> Valuators { get; }
public static RawInputModifiers ParseButtonState(int len, byte* buttons)
{
RawInputModifiers rv = default;
if (len > 0)
{
if (XIMaskIsSet(buttons, 1))
rv |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
rv |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
rv |= RawInputModifiers.RightMouseButton;
if (len > 1)
{
if (XIMaskIsSet(buttons, 8))
rv |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
rv |= RawInputModifiers.XButton2MouseButton;
}
}
return rv;
}
public ParsedDeviceEvent(XIDeviceEvent* ev)
{
Type = ev->evtype;
@ -298,27 +351,16 @@ namespace Avalonia.X11
if (state.HasFlag(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta;
if (ev->buttons.MaskLen > 0)
{
var buttons = ev->buttons.Mask;
if (XIMaskIsSet(buttons, 1))
Modifiers |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
Modifiers |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
Modifiers |= RawInputModifiers.RightMouseButton;
if (XIMaskIsSet(buttons, 8))
Modifiers |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
Modifiers |= RawInputModifiers.XButton2MouseButton;
}
Modifiers = ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Valuators = new Dictionary<int, double>();
Position = new Point(ev->event_x, ev->event_y);
var values = ev->valuators.Values;
for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if(ev->valuators.Mask != null)
for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease)
Button = ev->detail;
Detail = ev->detail;

43
src/Avalonia.X11/XIStructs.cs

@ -236,6 +236,34 @@ namespace Avalonia.X11
public XIModifierState mods;
public XIModifierState group;
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIEnterLeaveEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
public Bool send_event; /* true if this came from a SendEvent request */
public IntPtr display; /* Display the event was read from */
public int extension; /* XI extension offset */
public XiEventType evtype;
public IntPtr time;
public int deviceid;
public int sourceid;
public XiEnterLeaveDetail detail;
public IntPtr RootWindow;
public IntPtr EventWindow;
public IntPtr ChildWindow;
public double root_x;
public double root_y;
public double event_x;
public double event_y;
public int mode;
public int focus;
public int same_screen;
public XIButtonState buttons;
public XIModifierState mods;
public XIModifierState group;
}
[Flags]
public enum XiDeviceEventFlags : int
@ -286,5 +314,18 @@ namespace Avalonia.X11
XI_BarrierLeave = 26,
XI_LASTEVENT = XI_BarrierLeave,
}
enum XiEnterLeaveDetail
{
XINotifyAncestor = 0,
XINotifyVirtual = 1,
XINotifyInferior = 2,
XINotifyNonlinear = 3,
XINotifyNonlinearVirtual = 4,
XINotifyPointer = 5,
XINotifyPointerRoot = 6,
XINotifyDetailNone = 7
}
}

Loading…
Cancel
Save