diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000..c5a719ce90
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+open_collective: avalonia
diff --git a/.gitignore b/.gitignore
index 2b2c9c3d0d..971c945246 100644
--- a/.gitignore
+++ b/.gitignore
@@ -196,3 +196,5 @@ ModuleCache.noindex/
Build/Intermediates.noindex/
info.plist
build-intermediate
+obj-Direct2D1/
+obj-Skia/
diff --git a/dirs.proj b/dirs.proj
index 4939a158bb..e56320e73f 100644
--- a/dirs.proj
+++ b/dirs.proj
@@ -8,10 +8,11 @@
-
-
+
+
+
diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj
index 489cb228aa..2c5a09bee7 100644
--- a/packages/Avalonia/Avalonia.csproj
+++ b/packages/Avalonia/Avalonia.csproj
@@ -1,6 +1,7 @@
netstandard2.0;net461;netcoreapp2.0
+ Avalonia
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index 93f5611ec4..c35b4a7919 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -46,6 +46,8 @@ namespace ControlCatalog.NetCore
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
+ .With(new X11PlatformOptions {EnableMultiTouch = true})
+ .With(new Win32PlatformOptions {EnableMultitouch = true})
.UseSkia()
.UseReactiveUI();
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 9f1899acc5..1cddb9d295 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -31,6 +31,7 @@
+
diff --git a/samples/ControlCatalog/Pages/PointersPage.cs b/samples/ControlCatalog/Pages/PointersPage.cs
new file mode 100644
index 0000000000..a1359519e6
--- /dev/null
+++ b/samples/ControlCatalog/Pages/PointersPage.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Media;
+using Avalonia.Media.Immutable;
+
+namespace ControlCatalog.Pages
+{
+ public class PointersPage : Control
+ {
+ class PointerInfo
+ {
+ public Point Point { get; set; }
+ public Color Color { get; set; }
+ }
+
+ private static Color[] AllColors = new[]
+ {
+ Colors.Aqua,
+ Colors.Beige,
+ Colors.Chartreuse,
+ Colors.Coral,
+ Colors.Fuchsia,
+ Colors.Crimson,
+ Colors.Lavender,
+ Colors.Orange,
+ Colors.Orchid,
+ Colors.ForestGreen,
+ Colors.SteelBlue,
+ Colors.PapayaWhip,
+ Colors.PaleVioletRed,
+ Colors.Goldenrod,
+ Colors.Maroon,
+ Colors.Moccasin,
+ Colors.Navy,
+ Colors.Wheat,
+ Colors.Violet,
+ Colors.Sienna,
+ Colors.Indigo,
+ Colors.Honeydew
+ };
+
+ private Dictionary _pointers = new Dictionary();
+
+ public PointersPage()
+ {
+ ClipToBounds = true;
+ }
+
+ void UpdatePointer(PointerEventArgs e)
+ {
+ if (!_pointers.TryGetValue(e.Pointer, out var info))
+ {
+ if (e.RoutedEvent == PointerMovedEvent)
+ return;
+ var colors = AllColors.Except(_pointers.Values.Select(c => c.Color)).ToArray();
+ var color = colors[new Random().Next(0, colors.Length - 1)];
+ _pointers[e.Pointer] = info = new PointerInfo {Color = color};
+ }
+
+ info.Point = e.GetPosition(this);
+ InvalidateVisual();
+ }
+
+ protected override void OnPointerPressed(PointerPressedEventArgs e)
+ {
+ UpdatePointer(e);
+ e.Pointer.Capture(this);
+ base.OnPointerPressed(e);
+ }
+
+ protected override void OnPointerMoved(PointerEventArgs e)
+ {
+ UpdatePointer(e);
+ base.OnPointerMoved(e);
+ }
+
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
+ {
+ _pointers.Remove(e.Pointer);
+ InvalidateVisual();
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ context.FillRectangle(Brushes.Transparent, new Rect(default, Bounds.Size));
+ foreach (var pt in _pointers.Values)
+ {
+ var brush = new ImmutableSolidColorBrush(pt.Color);
+ context.DrawGeometry(brush, null, new EllipseGeometry(new Rect(pt.Point.X - 75, pt.Point.Y - 75,
+ 150, 150)));
+ }
+
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
index 112925ab0f..463d499aad 100644
--- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
+++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return null;
}
- RawMouseEventType? mouseEventType = null;
+ RawPointerEventType? mouseEventType = null;
var eventTime = DateTime.Now;
//Basic touch support
switch (e.Action)
@@ -42,17 +42,17 @@ namespace Avalonia.Android.Platform.Specific.Helpers
//may be bot flood the evnt system with too many event especially on not so powerfull mobile devices
if ((eventTime - _lastTouchMoveEventTime).TotalMilliseconds > 10)
{
- mouseEventType = RawMouseEventType.Move;
+ mouseEventType = RawPointerEventType.Move;
}
break;
case MotionEventActions.Down:
- mouseEventType = RawMouseEventType.LeftButtonDown;
+ mouseEventType = RawPointerEventType.LeftButtonDown;
break;
case MotionEventActions.Up:
- mouseEventType = RawMouseEventType.LeftButtonUp;
+ mouseEventType = RawPointerEventType.LeftButtonUp;
break;
}
@@ -75,14 +75,14 @@ namespace Avalonia.Android.Platform.Specific.Helpers
//we need to generate mouse move before first mouse down event
//as this is the way buttons are working every time
//otherwise there is a problem sometimes
- if (mouseEventType == RawMouseEventType.LeftButtonDown)
+ if (mouseEventType == RawPointerEventType.LeftButtonDown)
{
- var me = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
- RawMouseEventType.Move, _point, InputModifiers.None);
+ var me = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
+ RawPointerEventType.Move, _point, InputModifiers.None);
_view.Input(me);
}
- var mouseEvent = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
+ var mouseEvent = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
mouseEventType.Value, _point, InputModifiers.LeftMouseButton);
_view.Input(mouseEvent);
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index ec668f2a2b..df840464c1 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -150,7 +150,8 @@ namespace Avalonia.Build.Tasks
classType = typeSystem.TargetAssembly.FindType(tn.Text);
if (classType == null)
throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective);
- initialRoot.Type = new XamlIlAstClrTypeReference(classDirective, classType, false);
+ compiler.OverrideRootType(parsed,
+ new XamlIlAstClrTypeReference(classDirective, classType, false));
initialRoot.Children.Remove(classDirective);
}
diff --git a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
index 21d34ae4d6..27853a1540 100644
--- a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
+++ b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
@@ -1,6 +1,7 @@
netstandard2.0
+ Avalonia.Controls.DataGrid
diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs
index bbea3693cc..9f9fe5eae1 100644
--- a/src/Avalonia.Controls/Application.cs
+++ b/src/Avalonia.Controls/Application.cs
@@ -255,16 +255,13 @@ namespace Avalonia
if (MainWindow == null)
{
- Dispatcher.UIThread.Post(() =>
+ if (!mainWindow.IsVisible)
{
- if (!mainWindow.IsVisible)
- {
- mainWindow.Show();
- }
+ mainWindow.Show();
+ }
- MainWindow = mainWindow;
- });
- }
+ MainWindow = mainWindow;
+ }
return Run(new CancellationTokenSource());
}
@@ -362,7 +359,7 @@ namespace Avalonia
}
///
- bool IResourceProvider.TryGetResource(string key, out object value)
+ bool IResourceProvider.TryGetResource(object key, out object value)
{
value = null;
return (_resources?.TryGetResource(key, out value) ?? false) ||
diff --git a/src/Avalonia.Controls/Calendar/CalendarButton.cs b/src/Avalonia.Controls/Calendar/CalendarButton.cs
index 224d9b782b..53852defb3 100644
--- a/src/Avalonia.Controls/Calendar/CalendarButton.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarButton.cs
@@ -176,18 +176,5 @@ namespace Avalonia.Controls.Primitives
if (e.MouseButton == MouseButton.Left)
CalendarLeftMouseButtonUp?.Invoke(this, e);
}
-
- ///
- /// We need to simulate the MouseLeftButtonUp event for the
- /// CalendarButton that stays in Pressed state after MouseCapture is
- /// released since there is no actual MouseLeftButtonUp event for the
- /// release.
- ///
- /// Event arguments.
- internal void SendMouseLeftButtonUp(PointerReleasedEventArgs e)
- {
- e.Handled = false;
- base.OnPointerReleased(e);
- }
}
}
diff --git a/src/Avalonia.Controls/Calendar/CalendarDayButton.cs b/src/Avalonia.Controls/Calendar/CalendarDayButton.cs
index 1b36f92fd3..cb2a98e5ca 100644
--- a/src/Avalonia.Controls/Calendar/CalendarDayButton.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarDayButton.cs
@@ -234,18 +234,5 @@ namespace Avalonia.Controls.Primitives
if (e.MouseButton == MouseButton.Left)
CalendarDayButtonMouseUp?.Invoke(this, e);
}
-
- ///
- /// We need to simulate the MouseLeftButtonUp event for the
- /// CalendarDayButton that stays in Pressed state after MouseCapture is
- /// released since there is no actual MouseLeftButtonUp event for the
- /// release.
- ///
- /// Event arguments.
- internal void SendMouseLeftButtonUp(PointerReleasedEventArgs e)
- {
- e.Handled = false;
- base.OnPointerReleased(e);
- }
}
}
diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs
index fb6dacaf81..8232697c18 100644
--- a/src/Avalonia.Controls/Calendar/CalendarItem.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs
@@ -934,22 +934,6 @@ namespace Avalonia.Controls.Primitives
// The button is in Pressed state. Change the state to normal.
if (e.Device.Captured == b)
e.Device.Capture(null);
- // null check is added for unit tests
- if (_downEventArg != null)
- {
- var arg =
- new PointerReleasedEventArgs()
- {
- Device = _downEventArg.Device,
- MouseButton = _downEventArg.MouseButton,
- Handled = _downEventArg.Handled,
- InputModifiers = _downEventArg.InputModifiers,
- Route = _downEventArg.Route,
- Source = _downEventArg.Source
- };
-
- b.SendMouseLeftButtonUp(arg);
- }
_lastCalendarDayButton = b;
}
}
@@ -1221,21 +1205,7 @@ namespace Avalonia.Controls.Primitives
if (e.Device.Captured == b)
e.Device.Capture(null);
//b.ReleaseMouseCapture();
- if (_downEventArgYearView != null)
- {
- var args =
- new PointerReleasedEventArgs()
- {
- Device = _downEventArgYearView.Device,
- MouseButton = _downEventArgYearView.MouseButton,
- Handled = _downEventArgYearView.Handled,
- InputModifiers = _downEventArgYearView.InputModifiers,
- Route = _downEventArgYearView.Route,
- Source = _downEventArgYearView.Source
- };
-
- b.SendMouseLeftButtonUp(args);
- }
+
_lastCalendarButton = b;
}
}
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index d8473dc613..d0ab0a0c8b 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -337,12 +337,9 @@ namespace Avalonia.Controls
{
base.OnPointerEnter(e);
- RaiseEvent(new PointerEventArgs
- {
- Device = e.Device,
- RoutedEvent = PointerEnterItemEvent,
- Source = this,
- });
+ var point = e.GetPointerPoint(null);
+ RaiseEvent(new PointerEventArgs(PointerEnterItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
+ point.Properties, e.InputModifiers));
}
///
@@ -350,12 +347,9 @@ namespace Avalonia.Controls
{
base.OnPointerLeave(e);
- RaiseEvent(new PointerEventArgs
- {
- Device = e.Device,
- RoutedEvent = PointerLeaveItemEvent,
- Source = this,
- });
+ var point = e.GetPointerPoint(null);
+ RaiseEvent(new PointerEventArgs(PointerLeaveItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
+ point.Properties, e.InputModifiers));
}
///
diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
index 73854b9f60..5f63a44717 100644
--- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
+++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
@@ -373,9 +373,9 @@ namespace Avalonia.Controls.Platform
protected internal virtual void RawInput(RawInputEventArgs e)
{
- var mouse = e as RawMouseEventArgs;
+ var mouse = e as RawPointerEventArgs;
- if (mouse?.Type == RawMouseEventType.NonClientLeftButtonDown)
+ if (mouse?.Type == RawPointerEventType.NonClientLeftButtonDown)
{
Menu.Close();
}
diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs
index 0918da1a90..76f17332bf 100644
--- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs
+++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs
@@ -43,7 +43,7 @@ namespace Avalonia.Platform
_lastPosition = default(Point);
_allowedEffects = allowedEffects;
- using (_inputManager.PreProcess.OfType().Subscribe(ProcessMouseEvents))
+ using (_inputManager.PreProcess.OfType().Subscribe(ProcessMouseEvents))
{
using (_inputManager.PreProcess.OfType().Subscribe(ProcessKeyEvents))
{
@@ -153,7 +153,7 @@ namespace Avalonia.Platform
}
}
- private void ProcessMouseEvents(RawMouseEventArgs e)
+ private void ProcessMouseEvents(RawPointerEventArgs e)
{
if (!_initialInputModifiers.HasValue)
_initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS;
@@ -174,22 +174,22 @@ namespace Avalonia.Platform
switch (e.Type)
{
- case RawMouseEventType.LeftButtonDown:
- case RawMouseEventType.RightButtonDown:
- case RawMouseEventType.MiddleButtonDown:
- case RawMouseEventType.NonClientLeftButtonDown:
+ case RawPointerEventType.LeftButtonDown:
+ case RawPointerEventType.RightButtonDown:
+ case RawPointerEventType.MiddleButtonDown:
+ case RawPointerEventType.NonClientLeftButtonDown:
CancelDragging();
e.Handled = true;
return;
- case RawMouseEventType.LeaveWindow:
+ case RawPointerEventType.LeaveWindow:
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, e.Root, e.Position, e.InputModifiers); break;
- case RawMouseEventType.LeftButtonUp:
+ case RawPointerEventType.LeftButtonUp:
CheckDraggingAccepted(InputModifiers.LeftMouseButton); break;
- case RawMouseEventType.MiddleButtonUp:
+ case RawPointerEventType.MiddleButtonUp:
CheckDraggingAccepted(InputModifiers.MiddleMouseButton); break;
- case RawMouseEventType.RightButtonUp:
+ case RawPointerEventType.RightButtonUp:
CheckDraggingAccepted(InputModifiers.RightMouseButton); break;
- case RawMouseEventType.Move:
+ case RawPointerEventType.Move:
var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS;
if (_initialInputModifiers.Value != mods)
{
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index f349bcf059..e02d46c1df 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -421,9 +421,9 @@ namespace Avalonia.Controls.Primitives
private void ListenForNonClientClick(RawInputEventArgs e)
{
- var mouse = e as RawMouseEventArgs;
+ var mouse = e as RawPointerEventArgs;
- if (!StaysOpen && mouse?.Type == RawMouseEventType.NonClientLeftButtonDown)
+ if (!StaysOpen && mouse?.Type == RawPointerEventType.NonClientLeftButtonDown)
{
Close();
}
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 280c3ad93a..152b551f9a 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -380,6 +380,7 @@ namespace Avalonia.Controls.Primitives
}
break;
+ case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Reset:
SelectedIndex = IndexOf(Items, SelectedItem);
break;
@@ -644,20 +645,20 @@ namespace Avalonia.Controls.Primitives
/// The desired items.
internal static void SynchronizeItems(IList items, IEnumerable