diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index 52e09aba45..f8ae9f4249 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -60,7 +60,7 @@ namespace Avalonia.Platform { _lastPosition = pt; - RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects); + RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects, modifiers); var tl = root.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); tl.PlatformImpl?.Input(rawEvent); diff --git a/src/Avalonia.Input/DragDropDevice.cs b/src/Avalonia.Input/DragDropDevice.cs index 9fb100371f..0692b21c66 100644 --- a/src/Avalonia.Input/DragDropDevice.cs +++ b/src/Avalonia.Input/DragDropDevice.cs @@ -19,11 +19,11 @@ namespace Avalonia.Input return null; } - private DragDropEffects RaiseDragEvent(Interactive target, IInputElement inputRoot, Point point, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data) + private DragDropEffects RaiseDragEvent(Interactive target, IInputElement inputRoot, Point point, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data, InputModifiers modifiers) { if (target == null) return DragDropEffects.None; - var args = new DragEventArgs(routedEvent, data, target, inputRoot.TranslatePoint(point, target)) + var args = new DragEventArgs(routedEvent, data, target, inputRoot.TranslatePoint(point, target), modifiers) { RoutedEvent = routedEvent, DragEffects = operation @@ -32,24 +32,24 @@ namespace Avalonia.Input return args.DragEffects; } - private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects) + private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) { _lastTarget = GetTarget(inputRoot, point); - return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data); + return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } - private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects) + private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) { var target = GetTarget(inputRoot, point); if (target == _lastTarget) - return RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data); + return RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data, modifiers); try { if (_lastTarget != null) _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); - return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data); + return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } finally { @@ -71,11 +71,11 @@ namespace Avalonia.Input } } - private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects) + private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) { try { - return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data); + return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data, modifiers); } finally { @@ -94,16 +94,16 @@ namespace Avalonia.Input switch (e.Type) { case RawDragEventType.DragEnter: - e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects); + e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers); break; case RawDragEventType.DragOver: - e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects); + e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers); break; case RawDragEventType.DragLeave: DragLeave(e.InputRoot); break; case RawDragEventType.Drop: - e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects); + e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers); break; } } diff --git a/src/Avalonia.Input/DragEventArgs.cs b/src/Avalonia.Input/DragEventArgs.cs index 669fd846a1..915ee4ee5c 100644 --- a/src/Avalonia.Input/DragEventArgs.cs +++ b/src/Avalonia.Input/DragEventArgs.cs @@ -13,6 +13,8 @@ namespace Avalonia.Input public IDataObject Data { get; private set; } + public InputModifiers Modifiers { get; private set; } + public Point GetPosition(IVisual relativeTo) { var point = new Point(0, 0); @@ -29,12 +31,13 @@ namespace Avalonia.Input return point; } - public DragEventArgs(RoutedEvent routedEvent, IDataObject data, Interactive target, Point targetLocation) + public DragEventArgs(RoutedEvent routedEvent, IDataObject data, Interactive target, Point targetLocation, InputModifiers modifiers) : base(routedEvent) { this.Data = data; this._target = target; this._targetLocation = targetLocation; + this.Modifiers = modifiers; } } diff --git a/src/Avalonia.Input/Raw/RawDragEvent.cs b/src/Avalonia.Input/Raw/RawDragEvent.cs index 49125b4c07..80653b4873 100644 --- a/src/Avalonia.Input/Raw/RawDragEvent.cs +++ b/src/Avalonia.Input/Raw/RawDragEvent.cs @@ -11,9 +11,10 @@ namespace Avalonia.Input.Raw public IDataObject Data { get; } public DragDropEffects Effects { get; set; } public RawDragEventType Type { get; } + public InputModifiers Modifiers { get; } public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type, - IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects) + IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects, InputModifiers modifiers) :base(inputDevice, 0) { Type = type; @@ -21,6 +22,7 @@ namespace Avalonia.Input.Raw Location = location; Data = data; Effects = effects; + Modifiers = modifiers; } } } \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs index db7f29f05b..b528d84e4c 100644 --- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs +++ b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs @@ -164,8 +164,9 @@ namespace Avalonia.MonoMac var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask); DraggingInfo info = new DraggingInfo(sender); + var pt = TranslateLocalPoint(info.Location); - var args = new RawDragEvent(dragDevice, type, root, pt, info, dragOp); + var args = new RawDragEvent(dragDevice, type, root, pt, info, dragOp, GetModifiers(NSEvent.CurrentModifierFlags)); input(args); return DraggingInfo.ConvertDragOperation(args.Effects); } diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 13dcd9669d..9c18d52cea 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -250,7 +250,26 @@ namespace Avalonia.Skia { float currX = x; string subStr; + float measure; int len; + float factor; + switch (paint.TextAlign) + { + case SKTextAlign.Left: + factor = 0; + break; + case SKTextAlign.Center: + factor = 0.5f; + break; + case SKTextAlign.Right: + factor = 1; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + var textLine = Text.Substring(line.Start, line.Length); + currX -= paint.MeasureText(textLine) * factor; for (int i = line.Start; i < line.Start + line.Length;) { @@ -268,13 +287,15 @@ namespace Avalonia.Skia } subStr = Text.Substring(i, len); + measure = paint.MeasureText(subStr); + currX += measure * factor; ApplyWrapperTo(ref currentPaint, currentWrapper, ref currd, paint, canUseLcdRendering); canvas.DrawText(subStr, currX, origin.Y + line.Top + _lineOffset, paint); i += len; - currX += paint.MeasureText(subStr); + currX += measure * (1 - factor); } } } @@ -561,8 +582,8 @@ namespace Avalonia.Skia measured = LineBreak(Text, curOff, length, _paint, constraint, out trailingnumber); AvaloniaFormattedTextLine line = new AvaloniaFormattedTextLine(); - line.TextLength = measured; line.Start = curOff; + line.TextLength = measured; subString = Text.Substring(line.Start, line.TextLength); lineWidth = _paint.MeasureText(subString); line.Length = measured - trailingnumber; diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index b83002f54b..9cb22c68cd 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -226,6 +226,8 @@ namespace Avalonia.Win32.Interop MK_SHIFT = 0x0004, + MK_ALT = 0x0020, + MK_XBUTTON1 = 0x0020, MK_XBUTTON2 = 0x0040 @@ -1383,9 +1385,7 @@ namespace Avalonia.Win32.Interop Link = 4, Scroll = -2147483648, } - - - + [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("00000122-0000-0000-C000-000000000046")] diff --git a/src/Windows/Avalonia.Win32/OleDragSource.cs b/src/Windows/Avalonia.Win32/OleDragSource.cs index 522014abc0..a87995952a 100644 --- a/src/Windows/Avalonia.Win32/OleDragSource.cs +++ b/src/Windows/Avalonia.Win32/OleDragSource.cs @@ -11,10 +11,11 @@ namespace Avalonia.Win32 private const int DRAGDROP_S_DROP = 0x00040100; private const int DRAGDROP_S_CANCEL = 0x00040101; - private const int KEYSTATE_LEFTMB = 1; - private const int KEYSTATE_MIDDLEMB = 16; - private const int KEYSTATE_RIGHTMB = 2; - private static readonly int[] MOUSE_BUTTONS = new int[] { KEYSTATE_LEFTMB, KEYSTATE_MIDDLEMB, KEYSTATE_RIGHTMB }; + private static readonly int[] MOUSE_BUTTONS = new int[] { + (int)UnmanagedMethods.ModifierKeys.MK_LBUTTON, + (int)UnmanagedMethods.ModifierKeys.MK_MBUTTON, + (int)UnmanagedMethods.ModifierKeys.MK_RBUTTON + }; public int QueryContinueDrag(int fEscapePressed, int grfKeyState) { diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index 973564a3d1..6a10cc7e98 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -45,6 +45,26 @@ namespace Avalonia.Win32 return result; } + private static InputModifiers ConvertKeyState(int grfKeyState) + { + InputModifiers modifiers = InputModifiers.None; + var state = (UnmanagedMethods.ModifierKeys)grfKeyState; + + if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) + modifiers |= InputModifiers.LeftMouseButton; + if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) + modifiers |= InputModifiers.MiddleMouseButton; + if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) + modifiers |= InputModifiers.RightMouseButton; + if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_SHIFT)) + modifiers |= InputModifiers.Shift; + if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_CONTROL)) + modifiers |= InputModifiers.Control; + if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_ALT)) + modifiers |= InputModifiers.Alt; + return modifiers; + } + UnmanagedMethods.HRESULT IDropTarget.DragEnter(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect) { var dispatch = _tl?.Input; @@ -56,13 +76,15 @@ namespace Avalonia.Win32 _currentDrag = pDataObj as IDataObject; if (_currentDrag == null) _currentDrag = new OleDataObject(pDataObj); + var args = new RawDragEvent( _dragDevice, RawDragEventType.DragEnter, _target, GetDragLocation(pt), _currentDrag, - ConvertDropEffect(pdwEffect) + ConvertDropEffect(pdwEffect), + ConvertKeyState(grfKeyState) ); dispatch(args); pdwEffect = ConvertDropEffect(args.Effects); @@ -85,7 +107,8 @@ namespace Avalonia.Win32 _target, GetDragLocation(pt), _currentDrag, - ConvertDropEffect(pdwEffect) + ConvertDropEffect(pdwEffect), + ConvertKeyState(grfKeyState) ); dispatch(args); pdwEffect = ConvertDropEffect(args.Effects); @@ -98,12 +121,13 @@ namespace Avalonia.Win32 try { _tl?.Input(new RawDragEvent( - _dragDevice, - RawDragEventType.DragLeave, - _target, - default(Point), - null, - DragDropEffects.None + _dragDevice, + RawDragEventType.DragLeave, + _target, + default(Point), + null, + DragDropEffects.None, + InputModifiers.None )); return UnmanagedMethods.HRESULT.S_OK; } @@ -134,7 +158,8 @@ namespace Avalonia.Win32 _target, GetDragLocation(pt), _currentDrag, - ConvertDropEffect(pdwEffect) + ConvertDropEffect(pdwEffect), + ConvertKeyState(grfKeyState) ); dispatch(args); pdwEffect = ConvertDropEffect(args.Effects);