diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 06d6bdf3119..677fa2f4c5f 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -92,9 +92,17 @@ enum AvnRawMouseEventType RightButtonUp, MiddleButtonDown, MiddleButtonUp, + XButton1Down, + XButton1Up, + XButton2Down, + XButton2Up, Move, Wheel, - NonClientLeftButtonDown + NonClientLeftButtonDown, + TouchBegin, + TouchUpdate, + TouchEnd, + TouchCancel }; enum AvnRawKeyEventType @@ -112,7 +120,9 @@ enum AvnInputModifiers Windows = 8, LeftMouseButton = 16, RightMouseButton = 32, - MiddleMouseButton = 64 + MiddleMouseButton = 64, + XButton1MouseButton = 128, + XButton2MouseButton = 256 }; enum AvnWindowState diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 58dab388429..c54829d7501 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -716,7 +716,7 @@ @implementation AvnView AvnFramebuffer _swRenderedFrameBuffer; bool _queuedDisplayFromThread; NSTrackingArea* _area; - bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isMouseOver; + bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed, _isMouseOver; NSEvent* _lastMouseDownEvent; bool _lastKeyHandled; } @@ -942,9 +942,23 @@ - (void)mouseDown:(NSEvent *)event - (void)otherMouseDown:(NSEvent *)event { - _isMiddlePressed = true; _lastMouseDownEvent = event; - [self mouseEvent:event withType:MiddleButtonDown]; + + switch(event.buttonNumber) + { + case 3: + _isMiddlePressed = true; + [self mouseEvent:event withType:MiddleButtonDown]; + break; + case 4: + _isXButton1Pressed = true; + [self mouseEvent:event withType:XButton1Down]; + break; + case 5: + _isXButton2Pressed = true; + [self mouseEvent:event withType:XButton2Down]; + break; + } } - (void)rightMouseDown:(NSEvent *)event @@ -962,8 +976,21 @@ - (void)mouseUp:(NSEvent *)event - (void)otherMouseUp:(NSEvent *)event { - _isMiddlePressed = false; - [self mouseEvent:event withType:MiddleButtonUp]; + switch(event.buttonNumber) + { + case 3: + _isMiddlePressed = false; + [self mouseEvent:event withType:MiddleButtonUp]; + break; + case 4: + _isXButton1Pressed = false; + [self mouseEvent:event withType:XButton1Up]; + break; + case 5: + _isXButton2Pressed = false; + [self mouseEvent:event withType:XButton2Up]; + break; + } } - (void)rightMouseUp:(NSEvent *)event @@ -1062,6 +1089,10 @@ - (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod rv |= MiddleMouseButton; if (_isRightPressed) rv |= RightMouseButton; + if (_isXButton1Pressed) + rv |= XButton1MouseButton; + if (_isXButton2Pressed) + rv |= XButton2MouseButton; return (AvnInputModifiers)rv; } diff --git a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs index a91e6a3a487..d6cf3df5369 100644 --- a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs +++ b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs @@ -90,23 +90,17 @@ public void Render(DrawingContext context, Size size, Thickness borders, CornerR { var borderThickness = borders.Top; var top = borderThickness * 0.5; - var cornerRadius = (float)Math.Max(0, radii.TopLeft - borderThickness - top); - if (background != null) - { - var topLeft = new Point(borders.Left, borders.Top); - var bottomRight = new Point(size.Width - borders.Right, size.Height - borders.Bottom); - var innerRect = new Rect(topLeft, bottomRight); - context.FillRectangle(background, innerRect, cornerRadius); - } + IPen pen = null; - if (borderBrush != null && borderThickness > 0) + if (borderThickness > 0) { - var topLeft = new Point(top, top); - var bottomRight = new Point(size.Width - top, size.Height - top); - var outerRect = new Rect(topLeft, bottomRight); - context.DrawRectangle(new Pen(borderBrush, borderThickness), outerRect, (float)radii.TopLeft); + pen = new Pen(borderBrush, borderThickness); } + + var rect = new Rect(top, top, size.Width - borderThickness, size.Height - borderThickness); + + context.DrawRectangle(background, pen, rect, radii.TopLeft, radii.TopLeft); } } diff --git a/src/Avalonia.Input/IKeyboardDevice.cs b/src/Avalonia.Input/IKeyboardDevice.cs index 1a82f7d671f..144979523f4 100644 --- a/src/Avalonia.Input/IKeyboardDevice.cs +++ b/src/Avalonia.Input/IKeyboardDevice.cs @@ -48,6 +48,8 @@ public enum RawInputModifiers LeftMouseButton = 16, RightMouseButton = 32, MiddleMouseButton = 64, + XButton1MouseButton = 128, + XButton2MouseButton = 256, KeyboardMask = Alt | Control | Shift | Meta } diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index 4dcf0eee534..c74498171e2 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -120,6 +120,10 @@ int ButtonCount(PointerPointProperties props) rv++; if (props.IsRightButtonPressed) rv++; + if (props.IsXButton1Pressed) + rv++; + if (props.IsXButton2Pressed) + rv++; return rv; } @@ -142,6 +146,8 @@ private void ProcessRawEvent(RawPointerEventArgs e) case RawPointerEventType.LeftButtonDown: case RawPointerEventType.RightButtonDown: case RawPointerEventType.MiddleButtonDown: + case RawPointerEventType.XButton1Down: + case RawPointerEventType.XButton2Down: if (ButtonCount(props) > 1) e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers); else @@ -151,6 +157,8 @@ private void ProcessRawEvent(RawPointerEventArgs e) case RawPointerEventType.LeftButtonUp: case RawPointerEventType.RightButtonUp: case RawPointerEventType.MiddleButtonUp: + case RawPointerEventType.XButton1Up: + case RawPointerEventType.XButton2Up: if (ButtonCount(props) != 0) e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers); else @@ -186,12 +194,20 @@ PointerPointProperties CreateProperties(RawPointerEventArgs args) kind = PointerUpdateKind.MiddleButtonPressed; if (args.Type == RawPointerEventType.RightButtonDown) kind = PointerUpdateKind.RightButtonPressed; + if (args.Type == RawPointerEventType.XButton1Down) + kind = PointerUpdateKind.XButton1Pressed; + if (args.Type == RawPointerEventType.XButton2Down) + kind = PointerUpdateKind.XButton2Pressed; if (args.Type == RawPointerEventType.LeftButtonUp) kind = PointerUpdateKind.LeftButtonReleased; if (args.Type == RawPointerEventType.MiddleButtonUp) kind = PointerUpdateKind.MiddleButtonReleased; if (args.Type == RawPointerEventType.RightButtonUp) kind = PointerUpdateKind.RightButtonReleased; + if (args.Type == RawPointerEventType.XButton1Up) + kind = PointerUpdateKind.XButton1Released; + if (args.Type == RawPointerEventType.XButton2Up) + kind = PointerUpdateKind.XButton2Released; return new PointerPointProperties(args.InputModifiers, kind); } diff --git a/src/Avalonia.Input/PointerPoint.cs b/src/Avalonia.Input/PointerPoint.cs index 1068a0d4d4d..96132fdc90e 100644 --- a/src/Avalonia.Input/PointerPoint.cs +++ b/src/Avalonia.Input/PointerPoint.cs @@ -21,18 +21,24 @@ public sealed class PointerPointProperties public bool IsLeftButtonPressed { get; } public bool IsMiddleButtonPressed { get; } public bool IsRightButtonPressed { get; } + public bool IsXButton1Pressed { get; } + public bool IsXButton2Pressed { get; } + public PointerUpdateKind PointerUpdateKind { get; } + private PointerPointProperties() - { - + { } public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind) { PointerUpdateKind = kind; + IsLeftButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.LeftMouseButton); IsMiddleButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.MiddleMouseButton); IsRightButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.RightMouseButton); + IsXButton1Pressed = modifiers.HasFlagCustom(RawInputModifiers.XButton1MouseButton); + IsXButton2Pressed = modifiers.HasFlagCustom(RawInputModifiers.XButton2MouseButton); // The underlying input source might be reporting the previous state, // so make sure that we reflect the current state @@ -49,6 +55,14 @@ public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kin IsRightButtonPressed = true; if (kind == PointerUpdateKind.RightButtonReleased) IsRightButtonPressed = false; + if (kind == PointerUpdateKind.XButton1Pressed) + IsXButton1Pressed = true; + if (kind == PointerUpdateKind.XButton1Released) + IsXButton1Pressed = false; + if (kind == PointerUpdateKind.XButton2Pressed) + IsXButton2Pressed = true; + if (kind == PointerUpdateKind.XButton2Released) + IsXButton2Pressed = false; } public static PointerPointProperties None { get; } = new PointerPointProperties(); @@ -59,9 +73,13 @@ public enum PointerUpdateKind LeftButtonPressed, MiddleButtonPressed, RightButtonPressed, + XButton1Pressed, + XButton2Pressed, LeftButtonReleased, MiddleButtonReleased, RightButtonReleased, + XButton1Released, + XButton2Released, Other } diff --git a/src/Avalonia.Input/Raw/RawPointerEventArgs.cs b/src/Avalonia.Input/Raw/RawPointerEventArgs.cs index 56854c7d29f..4b2c95943d7 100644 --- a/src/Avalonia.Input/Raw/RawPointerEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawPointerEventArgs.cs @@ -14,6 +14,10 @@ public enum RawPointerEventType RightButtonUp, MiddleButtonDown, MiddleButtonUp, + XButton1Down, + XButton1Up, + XButton2Down, + XButton2Up, Move, Wheel, NonClientLeftButtonDown, diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 4c9bf9ebd4d..8aa0bac41a4 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -118,6 +118,42 @@ public void DrawGeometry(IBrush brush, IPen pen, Geometry geometry) } } + /// + /// Draws a rectangle with the specified Brush and Pen. + /// + /// The brush used to fill the rectangle, or null for no fill. + /// The pen used to stroke the rectangle, or null for no stroke. + /// The rectangle bounds. + /// The radius in the X dimension of the rounded corners. + /// This value will be clamped to the range of 0 to Width/2 + /// + /// The radius in the Y dimension of the rounded corners. + /// This value will be clamped to the range of 0 to Height/2 + /// + /// + /// The brush and the pen can both be null. If the brush is null, then no fill is performed. + /// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible. + /// + public void DrawRectangle(IBrush brush, IPen pen, Rect rect, double radiusX = 0, double radiusY = 0) + { + if (brush == null && !PenIsVisible(pen)) + { + return; + } + + if (Math.Abs(radiusX) > double.Epsilon) + { + radiusX = Math.Min(radiusX, rect.Width / 2); + } + + if (Math.Abs(radiusY) > double.Epsilon) + { + radiusY = Math.Min(radiusY, rect.Height / 2); + } + + PlatformImpl.DrawRectangle(brush, pen, rect, radiusX, radiusY); + } + /// /// Draws the outline of a rectangle. /// @@ -126,10 +162,7 @@ public void DrawGeometry(IBrush brush, IPen pen, Geometry geometry) /// The corner radius. public void DrawRectangle(IPen pen, Rect rect, float cornerRadius = 0.0f) { - if (PenIsVisible(pen)) - { - PlatformImpl.DrawRectangle(pen, rect, cornerRadius); - } + DrawRectangle(null, pen, rect, cornerRadius, cornerRadius); } /// @@ -162,10 +195,7 @@ public void DrawText(IBrush foreground, Point origin, FormattedText text) /// The corner radius. public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0.0f) { - if (brush != null && rect != Rect.Empty) - { - PlatformImpl.FillRectangle(brush, rect, cornerRadius); - } + DrawRectangle(brush, null, rect, cornerRadius, cornerRadius); } public readonly struct PushedState : IDisposable diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index f74c551fe04..5edb1c9760b 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -61,12 +61,22 @@ public interface IDrawingContextImpl : IDisposable void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry); /// - /// Draws the outline of a rectangle. + /// Draws a rectangle with the specified Brush and Pen. /// - /// The pen. + /// The brush used to fill the rectangle, or null for no fill. + /// The pen used to stroke the rectangle, or null for no stroke. /// The rectangle bounds. - /// The corner radius. - void DrawRectangle(IPen pen, Rect rect, float cornerRadius = 0.0f); + /// The radius in the X dimension of the rounded corners. + /// This value will be clamped to the range of 0 to Width/2 + /// + /// The radius in the Y dimension of the rounded corners. + /// This value will be clamped to the range of 0 to Height/2 + /// + /// + /// The brush and the pen can both be null. If the brush is null, then no fill is performed. + /// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible. + /// + void DrawRectangle(IBrush brush, IPen pen, Rect rect, double radiusX = 0, double radiusY = 0); /// /// Draws text. @@ -76,14 +86,6 @@ public interface IDrawingContextImpl : IDisposable /// The text. void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text); - /// - /// Draws a filled rectangle. - /// - /// The brush. - /// The rectangle bounds. - /// The corner radius. - void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0.0f); - /// /// Creates a new that can be used as a render layer /// for the current render target. diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index d9a68b236ad..2fa249f1010 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -445,7 +445,7 @@ private void RenderDirtyRects(IDrawingContextImpl context) foreach (var r in _dirtyRectsDisplay) { var brush = new ImmutableSolidColorBrush(Colors.Magenta, r.Opacity); - context.FillRectangle(brush, r.Rect); + context.DrawRectangle(brush,null, r.Rect); } } diff --git a/src/Avalonia.Visuals/Rendering/RendererBase.cs b/src/Avalonia.Visuals/Rendering/RendererBase.cs index e341f02901c..e39581fc57c 100644 --- a/src/Avalonia.Visuals/Rendering/RendererBase.cs +++ b/src/Avalonia.Visuals/Rendering/RendererBase.cs @@ -51,7 +51,7 @@ protected void RenderFps(IDrawingContextImpl context, Rect clientRect, int? laye var rect = new Rect(clientRect.Right - size.Width, 0, size.Width, size.Height); context.Transform = Matrix.Identity; - context.FillRectangle(Brushes.Black, rect); + context.DrawRectangle(Brushes.Black,null, rect); context.DrawText(Brushes.White, rect.TopLeft, _fpsText.PlatformImpl); } } diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index 3af56f52158..4fbfb02660f 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -152,13 +152,13 @@ public void DrawLine(IPen pen, Point p1, Point p2) } /// - public void DrawRectangle(IPen pen, Rect rect, float cornerRadius = 0) + public void DrawRectangle(IBrush brush, IPen pen, Rect rect, double radiusX = 0, double radiusY = 0) { var next = NextDrawAs(); - if (next == null || !next.Item.Equals(Transform, null, pen, rect, cornerRadius)) + if (next == null || !next.Item.Equals(Transform, brush, pen, rect, radiusX, radiusY)) { - Add(new RectangleNode(Transform, null, pen, rect, cornerRadius, CreateChildScene(pen.Brush))); + Add(new RectangleNode(Transform, brush, pen, rect, radiusX, radiusY, CreateChildScene(brush))); } else { @@ -190,21 +190,6 @@ public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) } } - /// - public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0) - { - var next = NextDrawAs(); - - if (next == null || !next.Item.Equals(Transform, brush, null, rect, cornerRadius)) - { - Add(new RectangleNode(Transform, brush, null, rect, cornerRadius, CreateChildScene(brush))); - } - else - { - ++_drawOperationindex; - } - } - public IRenderTargetBitmapImpl CreateLayer(Size size) { throw new NotSupportedException("Creating layers on a deferred drawing context not supported"); diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs index 0f3581b84c4..b40afe78c5f 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using System.Collections.Generic; using Avalonia.Media; using Avalonia.Media.Immutable; @@ -21,14 +22,16 @@ internal class RectangleNode : BrushDrawOperation /// The fill brush. /// The stroke pen. /// The rectangle to draw. - /// The rectangle corner radius. + /// The radius in the Y dimension of the rounded corners. + /// The radius in the X dimension of the rounded corners. /// Child scenes for drawing visual brushes. public RectangleNode( Matrix transform, IBrush brush, IPen pen, Rect rect, - float cornerRadius, + double radiusX, + double radiusY, IDictionary childScenes = null) : base(rect, transform, pen) { @@ -36,7 +39,8 @@ public RectangleNode( Brush = brush?.ToImmutable(); Pen = pen?.ToImmutable(); Rect = rect; - CornerRadius = cornerRadius; + RadiusX = radiusX; + RadiusY = radiusY; ChildScenes = childScenes; } @@ -61,9 +65,14 @@ public RectangleNode( public Rect Rect { get; } /// - /// Gets the rectangle corner radius. + /// The radius in the X dimension of the rounded corners. /// - public float CornerRadius { get; } + public double RadiusX { get; } + + /// + /// The radius in the Y dimension of the rounded corners. + /// + public double RadiusY { get; } /// public override IDictionary ChildScenes { get; } @@ -75,19 +84,21 @@ public RectangleNode( /// The fill of the other draw operation. /// The stroke of the other draw operation. /// The rectangle of the other draw operation. - /// The rectangle corner radius of the other draw operation. + /// + /// /// True if the draw operations are the same, otherwise false. /// /// The properties of the other draw operation are passed in as arguments to prevent /// allocation of a not-yet-constructed draw operation object. /// - public bool Equals(Matrix transform, IBrush brush, IPen pen, Rect rect, float cornerRadius) + public bool Equals(Matrix transform, IBrush brush, IPen pen, Rect rect, double radiusX, double radiusY) { return transform == Transform && - Equals(brush, Brush) && - Equals(Pen, pen) && - rect == Rect && - cornerRadius == CornerRadius; + Equals(brush, Brush) && + Equals(Pen, pen) && + rect == Rect && + Math.Abs(radiusX - RadiusX) < double.Epsilon && + Math.Abs(radiusY - RadiusY) < double.Epsilon; } /// @@ -95,15 +106,7 @@ public override void Render(IDrawingContextImpl context) { context.Transform = Transform; - if (Brush != null) - { - context.FillRectangle(Brush, Rect, CornerRadius); - } - - if (Pen != null) - { - context.DrawRectangle(Pen, Rect, CornerRadius); - } + context.DrawRectangle(Brush, Pen, Rect, RadiusX, RadiusY); } /// diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 32460fed860..6ff5b96f12a 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -351,10 +351,17 @@ void OnEventSync(XEvent ev) { if (ActivateTransientChildIfNeeded()) return; - if (ev.ButtonEvent.button < 4) - MouseEvent(ev.ButtonEvent.button == 1 ? RawPointerEventType.LeftButtonDown - : ev.ButtonEvent.button == 2 ? RawPointerEventType.MiddleButtonDown - : RawPointerEventType.RightButtonDown, ref ev, ev.ButtonEvent.state); + if (ev.ButtonEvent.button < 4 || ev.ButtonEvent.button == 8 || ev.ButtonEvent.button == 9) + MouseEvent( + ev.ButtonEvent.button switch + { + 1 => RawPointerEventType.LeftButtonDown, + 2 => RawPointerEventType.MiddleButtonDown, + 3 => RawPointerEventType.RightButtonDown, + 8 => RawPointerEventType.XButton1Down, + 9 => RawPointerEventType.XButton2Down + }, + ref ev, ev.ButtonEvent.state); else { var delta = ev.ButtonEvent.button == 4 @@ -372,10 +379,17 @@ void OnEventSync(XEvent ev) } else if (ev.type == XEventName.ButtonRelease) { - if (ev.ButtonEvent.button < 4) - MouseEvent(ev.ButtonEvent.button == 1 ? RawPointerEventType.LeftButtonUp - : ev.ButtonEvent.button == 2 ? RawPointerEventType.MiddleButtonUp - : RawPointerEventType.RightButtonUp, ref ev, ev.ButtonEvent.state); + if (ev.ButtonEvent.button < 4 || ev.ButtonEvent.button == 8 || ev.ButtonEvent.button == 9) + MouseEvent( + ev.ButtonEvent.button switch + { + 1 => RawPointerEventType.LeftButtonUp, + 2 => RawPointerEventType.MiddleButtonUp, + 3 => RawPointerEventType.RightButtonUp, + 8 => RawPointerEventType.XButton1Up, + 9 => RawPointerEventType.XButton2Up + }, + ref ev, ev.ButtonEvent.state); } else if (ev.type == XEventName.ConfigureNotify) { @@ -586,8 +600,12 @@ RawInputModifiers TranslateModifiers(XModifierMask state) rv |= RawInputModifiers.LeftMouseButton; if (state.HasFlag(XModifierMask.Button2Mask)) rv |= RawInputModifiers.RightMouseButton; - if (state.HasFlag(XModifierMask.Button2Mask)) + if (state.HasFlag(XModifierMask.Button3Mask)) rv |= RawInputModifiers.MiddleMouseButton; + if (state.HasFlag(XModifierMask.Button4Mask)) + rv |= RawInputModifiers.XButton1MouseButton; + if (state.HasFlag(XModifierMask.Button5Mask)) + rv |= RawInputModifiers.XButton2MouseButton; if (state.HasFlag(XModifierMask.ShiftMask)) rv |= RawInputModifiers.Shift; if (state.HasFlag(XModifierMask.ControlMask)) diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs index e37ed39bee3..ac14efe1331 100644 --- a/src/Avalonia.X11/XI2Manager.cs +++ b/src/Avalonia.X11/XI2Manager.cs @@ -240,11 +240,15 @@ void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev) if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease) { var down = ev.Type == XiEventType.XI_ButtonPress; - var type = - ev.Button == 1 ? (down ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp) - : ev.Button == 2 ? (down ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp) - : ev.Button == 3 ? (down ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp) - : (RawPointerEventType?)null; + var type = ev.Button switch + { + 1 => down ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp, + 2 => down ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp, + 3 => down ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp, + 8 => down ? RawPointerEventType.XButton1Down : RawPointerEventType.XButton1Up, + 9 => down ? RawPointerEventType.XButton2Down : RawPointerEventType.XButton2Up, + _ => (RawPointerEventType?)null + }; if (type.HasValue) client.ScheduleInput(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot, type.Value, ev.Position, ev.Modifiers)); @@ -283,12 +287,14 @@ public ParsedDeviceEvent(XIDeviceEvent* ev) 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; } Valuators = new Dictionary(); diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 47e651ce912..fe932150402 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -184,37 +184,40 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) } /// - public void DrawRectangle(IPen pen, Rect rect, float cornerRadius = 0) + public void DrawRectangle(IBrush brush, IPen pen, Rect rect, double radiusX, double radiusY) { - using (var paint = CreatePaint(pen, rect.Size)) - { - var rc = rect.ToSKRect(); + var rc = rect.ToSKRect(); + var isRounded = Math.Abs(radiusX) > double.Epsilon || Math.Abs(radiusX) > double.Epsilon; - if (Math.Abs(cornerRadius) < float.Epsilon) - { - Canvas.DrawRect(rc, paint.Paint); - } - else + if (brush != null) + { + using (var paint = CreatePaint(brush, rect.Size)) { - Canvas.DrawRoundRect(rc, cornerRadius, cornerRadius, paint.Paint); + if (isRounded) + { + Canvas.DrawRoundRect(rc, (float)radiusX, (float)radiusY, paint.Paint); + } + else + { + Canvas.DrawRect(rc, paint.Paint); + } + } } - } - /// - public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0) - { - using (var paint = CreatePaint(brush, rect.Size)) + if (pen?.Brush != null) { - var rc = rect.ToSKRect(); - - if (Math.Abs(cornerRadius) < float.Epsilon) - { - Canvas.DrawRect(rc, paint.Paint); - } - else + using (var paint = CreatePaint(pen, rect.Size)) { - Canvas.DrawRoundRect(rc, cornerRadius, cornerRadius, paint.Paint); + if (isRounded) + { + Canvas.DrawRoundRect(rc, (float)radiusX, (float)radiusY, paint.Paint); + } + else + { + Canvas.DrawRect(rc, paint.Paint); + } + } } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 39d801eb2fe..394c9b14d12 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -230,34 +230,64 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) } } - /// - /// Draws the outline of a rectangle. - /// - /// The pen. - /// The rectangle bounds. - /// The corner radius. - public void DrawRectangle(IPen pen, Rect rect, float cornerRadius) + /// + public void DrawRectangle(IBrush brush, IPen pen, Rect rect, double radiusX, double radiusY) { - using (var brush = CreateBrush(pen.Brush, rect.Size)) - using (var d2dStroke = pen.ToDirect2DStrokeStyle(_deviceContext)) + var rc = rect.ToDirect2D(); + var isRounded = Math.Abs(radiusX) > double.Epsilon || Math.Abs(radiusX) > double.Epsilon; + + if (brush != null) { - if (brush.PlatformBrush != null) + using (var b = CreateBrush(brush, rect.Size)) { - if (cornerRadius == 0) + if (b.PlatformBrush != null) { - _deviceContext.DrawRectangle( - rect.ToDirect2D(), - brush.PlatformBrush, - (float)pen.Thickness, - d2dStroke); + if (isRounded) + { + _deviceContext.FillRoundedRectangle( + new RoundedRectangle + { + Rect = new RawRectangleF( + (float)rect.X, + (float)rect.Y, + (float)rect.Right, + (float)rect.Bottom), + RadiusX = (float)radiusX, + RadiusY = (float)radiusY + }, + b.PlatformBrush); + } + else + { + _deviceContext.FillRectangle(rc, b.PlatformBrush); + } } - else + } + } + + if (pen?.Brush != null) + { + using (var wrapper = CreateBrush(pen.Brush, rect.Size)) + using (var d2dStroke = pen.ToDirect2DStrokeStyle(_deviceContext)) + { + if (wrapper.PlatformBrush != null) { - _deviceContext.DrawRoundedRectangle( - new RoundedRectangle { Rect = rect.ToDirect2D(), RadiusX = cornerRadius, RadiusY = cornerRadius }, - brush.PlatformBrush, - (float)pen.Thickness, - d2dStroke); + if (isRounded) + { + _deviceContext.DrawRoundedRectangle( + new RoundedRectangle { Rect = rc, RadiusX = (float)radiusX, RadiusY = (float)radiusY }, + wrapper.PlatformBrush, + (float)pen.Thickness, + d2dStroke); + } + else + { + _deviceContext.DrawRectangle( + rc, + wrapper.PlatformBrush, + (float)pen.Thickness, + d2dStroke); + } } } } @@ -286,41 +316,6 @@ public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) } } - /// - /// Draws a filled rectangle. - /// - /// The brush. - /// The rectangle bounds. - /// The corner radius. - public void FillRectangle(IBrush brush, Rect rect, float cornerRadius) - { - using (var b = CreateBrush(brush, rect.Size)) - { - if (b.PlatformBrush != null) - { - if (cornerRadius == 0) - { - _deviceContext.FillRectangle(rect.ToDirect2D(), b.PlatformBrush); - } - else - { - _deviceContext.FillRoundedRectangle( - new RoundedRectangle - { - Rect = new RawRectangleF( - (float)rect.X, - (float)rect.Y, - (float)rect.Right, - (float)rect.Bottom), - RadiusX = cornerRadius, - RadiusY = cornerRadius - }, - b.PlatformBrush); - } - } - } - } - public IRenderTargetBitmapImpl CreateLayer(Size size) { if (_layerFactory != null) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9a929bcfb5b..c88ed4e34f8 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -545,34 +545,42 @@ protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, In case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN: - if(ShouldIgnoreTouchEmulatedMessage()) + case UnmanagedMethods.WindowsMessage.WM_XBUTTONDOWN: + if (ShouldIgnoreTouchEmulatedMessage()) break; e = new RawPointerEventArgs( _mouseDevice, timestamp, _owner, - msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN - ? RawPointerEventType.LeftButtonDown - : msg == (int)UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN - ? RawPointerEventType.RightButtonDown - : RawPointerEventType.MiddleButtonDown, + (UnmanagedMethods.WindowsMessage)msg switch + { + UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN => RawPointerEventType.LeftButtonDown, + UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN => RawPointerEventType.RightButtonDown, + UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN => RawPointerEventType.MiddleButtonDown, + UnmanagedMethods.WindowsMessage.WM_XBUTTONDOWN => + HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Down : RawPointerEventType.XButton2Down + }, DipFromLParam(lParam), GetMouseModifiers(wParam)); break; case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP: - if(ShouldIgnoreTouchEmulatedMessage()) + case UnmanagedMethods.WindowsMessage.WM_XBUTTONUP: + if (ShouldIgnoreTouchEmulatedMessage()) break; e = new RawPointerEventArgs( _mouseDevice, timestamp, _owner, - msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONUP - ? RawPointerEventType.LeftButtonUp - : msg == (int)UnmanagedMethods.WindowsMessage.WM_RBUTTONUP - ? RawPointerEventType.RightButtonUp - : RawPointerEventType.MiddleButtonUp, + (UnmanagedMethods.WindowsMessage)msg switch + { + UnmanagedMethods.WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp, + UnmanagedMethods.WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp, + UnmanagedMethods.WindowsMessage.WM_MBUTTONUP => RawPointerEventType.MiddleButtonUp, + UnmanagedMethods.WindowsMessage.WM_XBUTTONUP => + HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Up : RawPointerEventType.XButton2Up, + }, DipFromLParam(lParam), GetMouseModifiers(wParam)); break; @@ -632,15 +640,19 @@ protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, In case UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN: + case UnmanagedMethods.WindowsMessage.WM_NCXBUTTONDOWN: e = new RawPointerEventArgs( _mouseDevice, timestamp, _owner, - msg == (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN - ? RawPointerEventType.NonClientLeftButtonDown - : msg == (int)UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN - ? RawPointerEventType.RightButtonDown - : RawPointerEventType.MiddleButtonDown, + (UnmanagedMethods.WindowsMessage)msg switch + { + UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType.NonClientLeftButtonDown, + UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN => RawPointerEventType.RightButtonDown, + UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN => RawPointerEventType.MiddleButtonDown, + UnmanagedMethods.WindowsMessage.WM_NCXBUTTONDOWN => + HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Down : RawPointerEventType.XButton2Down, + }, PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam)); break; case WindowsMessage.WM_TOUCH: @@ -783,6 +795,10 @@ static RawInputModifiers GetMouseModifiers(IntPtr wParam) modifiers |= RawInputModifiers.RightMouseButton; if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) modifiers |= RawInputModifiers.MiddleMouseButton; + if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_XBUTTON1)) + modifiers |= RawInputModifiers.XButton1MouseButton; + if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_XBUTTON2)) + modifiers |= RawInputModifiers.XButton2MouseButton; return modifiers; } @@ -1061,5 +1077,7 @@ PixelSize EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Size } } IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; + + private static int HighWord(int param) => param >> 16; } } diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs index e6cd800529b..97e234a55b0 100644 --- a/tests/Avalonia.RenderTests/Media/BitmapTests.cs +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -78,9 +78,9 @@ public void FramebufferRenderResultsShouldBeUsableAsBitmap(PixelFormat fmt) { ctx.Clear(Colors.Transparent); ctx.PushOpacity(0.8); - ctx.FillRectangle(Brushes.Chartreuse, new Rect(0, 0, 20, 100)); - ctx.FillRectangle(Brushes.Crimson, new Rect(20, 0, 20, 100)); - ctx.FillRectangle(Brushes.Gold, new Rect(40, 0, 20, 100)); + ctx.DrawRectangle(Brushes.Chartreuse, null, new Rect(0, 0, 20, 100)); + ctx.DrawRectangle(Brushes.Crimson, null, new Rect(20, 0, 20, 100)); + ctx.DrawRectangle(Brushes.Gold,null, new Rect(40, 0, 20, 100)); ctx.PopOpacity(); } @@ -90,8 +90,8 @@ public void FramebufferRenderResultsShouldBeUsableAsBitmap(PixelFormat fmt) { using (var ctx = rtb.CreateDrawingContext(null)) { - ctx.FillRectangle(Brushes.Blue, new Rect(0, 0, 100, 100)); - ctx.FillRectangle(Brushes.Pink, new Rect(0, 20, 100, 10)); + ctx.DrawRectangle(Brushes.Blue, null, new Rect(0, 0, 100, 100)); + ctx.DrawRectangle(Brushes.Pink, null, new Rect(0, 20, 100, 10)); var rc = new Rect(0, 0, 60, 60); ctx.DrawImage(bmp.PlatformImpl, 1, rc, rc); diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index 6063a382a06..2061caa3203 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs @@ -466,7 +466,7 @@ public void Should_Push_Opacity_For_Controls_With_Less_Than_1_Opacity() var animation = new BehaviorSubject(0.5); context.Verify(x => x.PushOpacity(0.5), Times.Once); - context.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once); + context.Verify(x => x.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0), Times.Once); context.Verify(x => x.PopOpacity(), Times.Once); } @@ -496,7 +496,7 @@ public void Should_Not_Draw_Controls_With_0_Opacity() var animation = new BehaviorSubject(0.5); context.Verify(x => x.PushOpacity(0.5), Times.Never); - context.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Never); + context.Verify(x => x.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0), Times.Never); context.Verify(x => x.PopOpacity(), Times.Never); } @@ -522,7 +522,7 @@ public void Should_Push_Opacity_Mask() var animation = new BehaviorSubject(0.5); context.Verify(x => x.PushOpacityMask(Brushes.Green, new Rect(0, 0, 100, 100)), Times.Once); - context.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once); + context.Verify(x => x.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0), Times.Once); context.Verify(x => x.PopOpacityMask(), Times.Once); } @@ -641,7 +641,7 @@ public void Should_Not_Push_Opacity_For_Transparent_Layer_Root_Control() var context = GetLayerContext(target, border); context.Verify(x => x.PushOpacity(0.5), Times.Never); - context.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once); + context.Verify(x => x.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0), Times.Once); context.Verify(x => x.PopOpacity(), Times.Never); } diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs index f57c73c45cf..5fe92ba039d 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs @@ -100,20 +100,18 @@ public void Should_Add_DrawOperations() using (target.BeginUpdate(node)) { - target.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100)); - target.DrawRectangle(new Pen(Brushes.Green, 1), new Rect(0, 0, 100, 100)); + target.DrawRectangle(Brushes.Red, new Pen(Brushes.Green, 1), new Rect(0, 0, 100, 100)); } - Assert.Equal(2, node.DrawOperations.Count); + Assert.Equal(1, node.DrawOperations.Count); Assert.IsType(node.DrawOperations[0].Item); - Assert.IsType(node.DrawOperations[1].Item); } [Fact] public void Should_Not_Replace_Identical_DrawOperation() { var node = new VisualNode(new TestRoot(), null); - var operation = RefCountable.Create(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0)); + var operation = RefCountable.Create(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0)); var layers = new SceneLayers(node.Visual); var target = new DeferredDrawingContextImpl(null, layers); @@ -122,7 +120,7 @@ public void Should_Not_Replace_Identical_DrawOperation() using (target.BeginUpdate(node)) { - target.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100)); + target.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100)); } Assert.Equal(1, node.DrawOperations.Count); @@ -135,7 +133,7 @@ public void Should_Not_Replace_Identical_DrawOperation() public void Should_Replace_Different_DrawOperation() { var node = new VisualNode(new TestRoot(), null); - var operation = RefCountable.Create(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0)); + var operation = RefCountable.Create(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0)); var layers = new SceneLayers(node.Visual); var target = new DeferredDrawingContextImpl(null, layers); @@ -144,7 +142,7 @@ public void Should_Replace_Different_DrawOperation() using (target.BeginUpdate(node)) { - target.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100)); + target.DrawRectangle(Brushes.Green, null, new Rect(0, 0, 100, 100)); } Assert.Equal(1, node.DrawOperations.Count); @@ -157,7 +155,7 @@ public void Should_Replace_Different_DrawOperation() public void Should_Update_DirtyRects() { var node = new VisualNode(new TestRoot(), null); - var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0); + var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0); var layers = new SceneLayers(node.Visual); var target = new DeferredDrawingContextImpl(null, layers); @@ -165,7 +163,7 @@ public void Should_Update_DirtyRects() using (target.BeginUpdate(node)) { - target.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100)); + target.DrawRectangle(Brushes.Green, null, new Rect(0, 0, 100, 100)); } Assert.Equal(new Rect(0, 0, 100, 100), layers.Single().Dirty.Single()); @@ -192,8 +190,8 @@ public void Should_Trim_DrawOperations() using (target.BeginUpdate(node)) { - target.FillRectangle(Brushes.Green, new Rect(0, 0, 10, 100)); - target.FillRectangle(Brushes.Blue, new Rect(0, 0, 20, 100)); + target.DrawRectangle(Brushes.Green, null, new Rect(0, 0, 10, 100)); + target.DrawRectangle(Brushes.Blue, null, new Rect(0, 0, 20, 100)); } Assert.Equal(2, node.DrawOperations.Count); @@ -208,7 +206,7 @@ public void Should_Trim_DrawOperations() public void Trimmed_DrawOperations_Releases_Reference() { var node = new VisualNode(new TestRoot(), null); - var operation = RefCountable.Create(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0)); + var operation = RefCountable.Create(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0, 0)); var layers = new SceneLayers(node.Visual); var target = new DeferredDrawingContextImpl(null, layers); @@ -218,7 +216,7 @@ public void Trimmed_DrawOperations_Releases_Reference() using (target.BeginUpdate(node)) { - target.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100)); + target.DrawRectangle(Brushes.Green, null, new Rect(0, 0, 100, 100)); } Assert.Equal(1, node.DrawOperations.Count);