diff --git a/readme.md b/readme.md
index 96cfde3eb2..2b26cbdd1a 100644
--- a/readme.md
+++ b/readme.md
@@ -35,7 +35,7 @@ https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master/artifacts
## Documentation
-As mentioned above, Avalonia is still in alpha and as such there's not much documentation yet. You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia).
+As mentioned above, Avalonia is still in beta and as such there's not much documentation yet. You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia).
There's also a high-level [architecture document](http://avaloniaui.net/architecture/project-structure) that is currently a little bit out of date, and I've also started writing blog posts on Avalonia at http://grokys.github.io/.
diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs
index b151cabf43..a2048005a4 100644
--- a/samples/ControlCatalog.Desktop/Program.cs
+++ b/samples/ControlCatalog.Desktop/Program.cs
@@ -10,6 +10,7 @@ namespace ControlCatalog
{
internal class Program
{
+ [STAThread]
static void Main(string[] args)
{
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index 346535d39d..b45a93455e 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -9,8 +9,10 @@ namespace ControlCatalog.NetCore
{
static class Program
{
+
static void Main(string[] args)
{
+ Thread.CurrentThread.TrySetApartmentState(ApartmentState.STA);
if (args.Contains("--wait-for-attach"))
{
Console.WriteLine("Attach debugger and use 'Set next statement'");
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index 862de9d320..b8a8479a49 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -1,201 +1,17 @@
- netstandard2.0
- False
- false
+ netstandard2.0
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
- Designer
-
-
-
-
- App.xaml
-
-
- MainView.xaml
-
-
- DecoratedWindow.xaml
-
-
- MainWindow.xaml
-
-
- DialogsPage.xaml
-
-
- BorderPage.xaml
-
-
- AutoCompleteBoxPage.xaml
-
-
- ButtonPage.xaml
-
-
- CalendarPage.xaml
-
-
- CanvasPage.xaml
-
-
- CarouselPage.xaml
-
-
- ContextMenuPage.xaml
-
-
- CheckBoxPage.xaml
-
-
- DropDownPage.xaml
-
-
- DatePickerPage.xaml
-
-
- ExpanderPage.xaml
-
-
- ImagePage.xaml
+
+ %(Filename)
-
- LayoutTransformControlPage.xaml
-
-
- MenuPage.xaml
-
-
- ProgressBarPage.xaml
-
-
- RadioButtonPage.xaml
-
-
- SliderPage.xaml
-
-
- TreeViewPage.xaml
-
-
- TextBoxPage.xaml
-
-
- ToolTipPage.xaml
-
-
- ButtonSpinnerPage.xaml
-
-
- NumericUpDownPage.xaml
-
-
-
-
-
-
-
-
-
-
-
-
+
Designer
+
+
@@ -212,20 +28,6 @@
-
-
-
-
-
- Designer
-
-
-
-
- MSBuild:Compile
-
-
-
-
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index a0e0df450b..1107d34b3e 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -15,6 +15,7 @@
+
diff --git a/samples/ControlCatalog/Pages/DragAndDropPage.xaml b/samples/ControlCatalog/Pages/DragAndDropPage.xaml
new file mode 100644
index 0000000000..af679d2f9a
--- /dev/null
+++ b/samples/ControlCatalog/Pages/DragAndDropPage.xaml
@@ -0,0 +1,19 @@
+
+
+ Drag+Drop
+ Example of Drag+Drop capabilities
+
+
+
+ Drag Me
+
+
+ Drop some text or files here
+
+
+
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs b/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
new file mode 100644
index 0000000000..718f21314e
--- /dev/null
+++ b/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
@@ -0,0 +1,71 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ControlCatalog.Pages
+{
+ public class DragAndDropPage : UserControl
+ {
+ private TextBlock _DropState;
+ private TextBlock _DragState;
+ private Border _DragMe;
+ private int DragCount = 0;
+
+ public DragAndDropPage()
+ {
+ this.InitializeComponent();
+
+ _DragMe.PointerPressed += DoDrag;
+
+ AddHandler(DragDrop.DropEvent, Drop);
+ AddHandler(DragDrop.DragOverEvent, DragOver);
+ }
+
+ private async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
+ {
+ DataObject dragData = new DataObject();
+ dragData.Set(DataFormats.Text, $"You have dragged text {++DragCount} times");
+
+ var result = await DragDrop.DoDragDrop(dragData, DragDropEffects.Copy);
+ switch(result)
+ {
+ case DragDropEffects.Copy:
+ _DragState.Text = "The text was copied"; break;
+ case DragDropEffects.Link:
+ _DragState.Text = "The text was linked"; break;
+ case DragDropEffects.None:
+ _DragState.Text = "The drag operation was canceled"; break;
+ }
+ }
+
+ private void DragOver(object sender, DragEventArgs e)
+ {
+ // Only allow Copy or Link as Drop Operations.
+ e.DragEffects = e.DragEffects & (DragDropEffects.Copy | DragDropEffects.Link);
+
+ // Only allow if the dragged data contains text or filenames.
+ if (!e.Data.Contains(DataFormats.Text) && !e.Data.Contains(DataFormats.FileNames))
+ e.DragEffects = DragDropEffects.None;
+ }
+
+ private void Drop(object sender, DragEventArgs e)
+ {
+ if (e.Data.Contains(DataFormats.Text))
+ _DropState.Text = e.Data.GetText();
+ else if (e.Data.Contains(DataFormats.FileNames))
+ _DropState.Text = string.Join(Environment.NewLine, e.Data.GetFileNames());
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+
+ _DropState = this.Find("DropState");
+ _DragState = this.Find("DragState");
+ _DragMe = this.Find("DragMe");
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Properties/AssemblyInfo.cs b/samples/ControlCatalog/Properties/AssemblyInfo.cs
deleted file mode 100644
index 30c069d7d8..0000000000
--- a/samples/ControlCatalog/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("ControlCatalog")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ControlCatalog")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("61bec86c-f307-4295-b5b8-9428610d7d55")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Avalonia.Base/Utilities/StringTokenizer.cs b/src/Avalonia.Base/Utilities/StringTokenizer.cs
new file mode 100644
index 0000000000..2559e52932
--- /dev/null
+++ b/src/Avalonia.Base/Utilities/StringTokenizer.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Globalization;
+using static System.Char;
+
+namespace Avalonia.Utilities
+{
+ public struct StringTokenizer : IDisposable
+ {
+ private const char DefaultSeparatorChar = ',';
+
+ private readonly string _s;
+ private readonly int _length;
+ private readonly char _separator;
+ private readonly string _exceptionMessage;
+ private readonly IFormatProvider _formatProvider;
+ private int _index;
+ private int _tokenIndex;
+ private int _tokenLength;
+
+ public StringTokenizer(string s, IFormatProvider formatProvider, string exceptionMessage = null)
+ : this(s, GetSeparatorFromFormatProvider(formatProvider), exceptionMessage)
+ {
+ _formatProvider = formatProvider;
+ }
+
+ public StringTokenizer(string s, char separator = DefaultSeparatorChar, string exceptionMessage = null)
+ {
+ _s = s ?? throw new ArgumentNullException(nameof(s));
+ _length = s?.Length ?? 0;
+ _separator = separator;
+ _exceptionMessage = exceptionMessage;
+ _formatProvider = CultureInfo.InvariantCulture;
+ _index = 0;
+ _tokenIndex = -1;
+ _tokenLength = 0;
+
+ while (_index < _length && IsWhiteSpace(_s, _index))
+ {
+ _index++;
+ }
+ }
+
+ public string CurrentToken => _tokenIndex < 0 ? null : _s.Substring(_tokenIndex, _tokenLength);
+
+ public void Dispose()
+ {
+ if (_index != _length)
+ {
+ throw GetFormatException();
+ }
+ }
+
+ public bool TryReadInt32(out Int32 result, char? separator = null)
+ {
+ var success = TryReadString(out var stringResult, separator);
+ result = success ? int.Parse(stringResult, _formatProvider) : 0;
+ return success;
+ }
+
+ public int ReadInt32(char? separator = null)
+ {
+ if (!TryReadInt32(out var result, separator))
+ {
+ throw GetFormatException();
+ }
+
+ return result;
+ }
+
+ public bool TryReadDouble(out double result, char? separator = null)
+ {
+ var success = TryReadString(out var stringResult, separator);
+ result = success ? double.Parse(stringResult, _formatProvider) : 0;
+ return success;
+ }
+
+ public double ReadDouble(char? separator = null)
+ {
+ if (!TryReadDouble(out var result, separator))
+ {
+ throw GetFormatException();
+ }
+
+ return result;
+ }
+
+ public bool TryReadString(out string result, char? separator = null)
+ {
+ var success = TryReadToken(separator ?? _separator);
+ result = CurrentToken;
+ return success;
+ }
+
+ public string ReadString(char? separator = null)
+ {
+ if (!TryReadString(out var result, separator))
+ {
+ throw GetFormatException();
+ }
+
+ return result;
+ }
+
+ private bool TryReadToken(char separator)
+ {
+ _tokenIndex = -1;
+
+ if (_index >= _length)
+ {
+ return false;
+ }
+
+ var c = _s[_index];
+
+ var index = _index;
+ var length = 0;
+
+ while (_index < _length)
+ {
+ c = _s[_index];
+
+ if (IsWhiteSpace(c) || c == separator)
+ {
+ break;
+ }
+
+ _index++;
+ length++;
+ }
+
+ SkipToNextToken(separator);
+
+ _tokenIndex = index;
+ _tokenLength = length;
+
+ if (_tokenLength < 1)
+ {
+ throw GetFormatException();
+ }
+
+ return true;
+ }
+
+ private void SkipToNextToken(char separator)
+ {
+ if (_index < _length)
+ {
+ var c = _s[_index];
+
+ if (c != separator && !IsWhiteSpace(c))
+ {
+ throw GetFormatException();
+ }
+
+ var length = 0;
+
+ while (_index < _length)
+ {
+ c = _s[_index];
+
+ if (c == separator)
+ {
+ length++;
+ _index++;
+
+ if (length > 1)
+ {
+ throw GetFormatException();
+ }
+ }
+ else
+ {
+ if (!IsWhiteSpace(c))
+ {
+ break;
+ }
+
+ _index++;
+ }
+ }
+
+ if (length > 0 && _index >= _length)
+ {
+ throw GetFormatException();
+ }
+ }
+ }
+
+ private FormatException GetFormatException() =>
+ _exceptionMessage != null ? new FormatException(_exceptionMessage) : new FormatException();
+
+ private static char GetSeparatorFromFormatProvider(IFormatProvider provider)
+ {
+ var c = DefaultSeparatorChar;
+
+ var formatInfo = NumberFormatInfo.GetInstance(provider);
+ if (formatInfo.NumberDecimalSeparator.Length > 0 && c == formatInfo.NumberDecimalSeparator[0])
+ {
+ c = ';';
+ }
+
+ return c;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs
index 06c1a8b4cc..6fdca557eb 100644
--- a/src/Avalonia.Controls/Application.cs
+++ b/src/Avalonia.Controls/Application.cs
@@ -2,16 +2,17 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Reactive.Concurrency;
using System.Threading;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
using Avalonia.Layout;
-using Avalonia.Rendering;
+using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.Threading;
-using System.Reactive.Concurrency;
namespace Avalonia
{
@@ -234,7 +235,9 @@ namespace Avalonia
.Bind().ToConstant(_styler)
.Bind().ToSingleton()
.Bind().ToConstant(this)
- .Bind().ToConstant(AvaloniaScheduler.Instance);
+ .Bind().ToConstant(AvaloniaScheduler.Instance)
+ .Bind().ToConstant(DragDropDevice.Instance)
+ .Bind().ToTransient();
}
}
}
diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs
index fdb04f4ade..78dc994df7 100644
--- a/src/Avalonia.Controls/ContextMenu.cs
+++ b/src/Avalonia.Controls/ContextMenu.cs
@@ -19,7 +19,7 @@ namespace Avalonia.Controls
{
ContextMenuProperty.Changed.Subscribe(ContextMenuChanged);
- MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true);
+ MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true);
}
///
@@ -75,13 +75,14 @@ namespace Avalonia.Controls
{
if (control != null)
{
- if(_popup == null)
+ if (_popup == null)
{
_popup = new Popup()
{
PlacementMode = PlacementMode.Pointer,
PlacementTarget = control,
- StaysOpen = false
+ StaysOpen = false,
+ ObeyScreenEdges = true
};
_popup.Closed += PopupClosed;
diff --git a/src/Avalonia.Controls/GridLength.cs b/src/Avalonia.Controls/GridLength.cs
index c711553e05..789953a249 100644
--- a/src/Avalonia.Controls/GridLength.cs
+++ b/src/Avalonia.Controls/GridLength.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 Avalonia.Utilities;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -210,7 +211,13 @@ namespace Avalonia.Controls
/// The .
public static IEnumerable ParseLengths(string s, CultureInfo culture)
{
- return s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Parse(x, culture));
+ using (var tokenizer = new StringTokenizer(s, culture))
+ {
+ while (tokenizer.TryReadString(out var item))
+ {
+ yield return Parse(item, culture);
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs
new file mode 100644
index 0000000000..e136efe2a9
--- /dev/null
+++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Linq;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
+using Avalonia.Threading;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Platform
+{
+ class InProcessDragSource : IPlatformDragSource
+ {
+ private const InputModifiers MOUSE_INPUTMODIFIERS = InputModifiers.LeftMouseButton|InputModifiers.MiddleMouseButton|InputModifiers.RightMouseButton;
+ private readonly IDragDropDevice _dragDrop;
+ private readonly IInputManager _inputManager;
+ private readonly Subject _result = new Subject();
+
+ private DragDropEffects _allowedEffects;
+ private IDataObject _draggedData;
+ private IInputElement _lastRoot;
+ private Point _lastPosition;
+ private StandardCursorType _lastCursorType;
+ private object _originalCursor;
+ private InputModifiers? _initialInputModifiers;
+
+ public InProcessDragSource()
+ {
+ _inputManager = AvaloniaLocator.Current.GetService();
+ _dragDrop = AvaloniaLocator.Current.GetService();
+ }
+
+ public async Task DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+ {
+ Dispatcher.UIThread.VerifyAccess();
+ if (_draggedData == null)
+ {
+ _draggedData = data;
+ _lastRoot = null;
+ _lastPosition = default(Point);
+ _allowedEffects = allowedEffects;
+
+ using (_inputManager.PreProcess.OfType().Subscribe(ProcessMouseEvents))
+ {
+ using (_inputManager.PreProcess.OfType().Subscribe(ProcessKeyEvents))
+ {
+ var effect = await _result.FirstAsync();
+ return effect;
+ }
+ }
+ }
+ return DragDropEffects.None;
+ }
+
+
+ private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputElement root, Point pt, InputModifiers modifiers)
+ {
+ _lastPosition = pt;
+
+ RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects);
+ var tl = root.GetSelfAndVisualAncestors().OfType().FirstOrDefault();
+ tl.PlatformImpl.Input(rawEvent);
+
+ var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers);
+ UpdateCursor(root, effect);
+ return effect;
+ }
+
+ private DragDropEffects GetPreferredEffect(DragDropEffects effect, InputModifiers modifiers)
+ {
+ if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None)
+ return effect; // No need to check for the modifiers.
+ if (effect.HasFlag(DragDropEffects.Link) && modifiers.HasFlag(InputModifiers.Alt))
+ return DragDropEffects.Link;
+ if (effect.HasFlag(DragDropEffects.Copy) && modifiers.HasFlag(InputModifiers.Control))
+ return DragDropEffects.Copy;
+ return DragDropEffects.Move;
+ }
+
+ private StandardCursorType GetCursorForDropEffect(DragDropEffects effects)
+ {
+ if (effects.HasFlag(DragDropEffects.Copy))
+ return StandardCursorType.DragCopy;
+ if (effects.HasFlag(DragDropEffects.Move))
+ return StandardCursorType.DragMove;
+ if (effects.HasFlag(DragDropEffects.Link))
+ return StandardCursorType.DragLink;
+ return StandardCursorType.No;
+ }
+
+ private void UpdateCursor(IInputElement root, DragDropEffects effect)
+ {
+ if (_lastRoot != root)
+ {
+ if (_lastRoot is InputElement ieLast)
+ {
+ if (_originalCursor == AvaloniaProperty.UnsetValue)
+ ieLast.ClearValue(InputElement.CursorProperty);
+ else
+ ieLast.Cursor = _originalCursor as Cursor;
+ }
+
+ if (root is InputElement ieNew)
+ {
+ if (!ieNew.IsSet(InputElement.CursorProperty))
+ _originalCursor = AvaloniaProperty.UnsetValue;
+ else
+ _originalCursor = root.Cursor;
+ }
+ else
+ _originalCursor = null;
+
+ _lastCursorType = StandardCursorType.Arrow;
+ _lastRoot = root;
+ }
+
+ if (root is InputElement ie)
+ {
+ var ct = GetCursorForDropEffect(effect);
+ if (ct != _lastCursorType)
+ {
+ _lastCursorType = ct;
+ ie.Cursor = new Cursor(ct);
+ }
+ }
+ }
+
+ private void CancelDragging()
+ {
+ if (_lastRoot != null)
+ RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, InputModifiers.None);
+ UpdateCursor(null, DragDropEffects.None);
+ _result.OnNext(DragDropEffects.None);
+ }
+
+ private void ProcessKeyEvents(RawKeyEventArgs e)
+ {
+ if (e.Type == RawKeyEventType.KeyDown && e.Key == Key.Escape)
+ {
+ if (_lastRoot != null)
+ RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, e.Modifiers);
+ UpdateCursor(null, DragDropEffects.None);
+ _result.OnNext(DragDropEffects.None);
+ e.Handled = true;
+ }
+ else if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl || e.Key == Key.LeftAlt || e.Key == Key.RightAlt)
+ RaiseEventAndUpdateCursor(RawDragEventType.DragOver, _lastRoot, _lastPosition, e.Modifiers);
+ }
+
+ private void ProcessMouseEvents(RawMouseEventArgs e)
+ {
+ if (!_initialInputModifiers.HasValue)
+ _initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS;
+
+
+ void CheckDraggingAccepted(InputModifiers changedMouseButton)
+ {
+ if (_initialInputModifiers.Value.HasFlag(changedMouseButton))
+ {
+ var result = RaiseEventAndUpdateCursor(RawDragEventType.Drop, e.Root, e.Position, e.InputModifiers);
+ UpdateCursor(null, DragDropEffects.None);
+ _result.OnNext(result);
+ }
+ else
+ CancelDragging();
+ e.Handled = true;
+ }
+
+ switch (e.Type)
+ {
+ case RawMouseEventType.LeftButtonDown:
+ case RawMouseEventType.RightButtonDown:
+ case RawMouseEventType.MiddleButtonDown:
+ case RawMouseEventType.NonClientLeftButtonDown:
+ CancelDragging();
+ e.Handled = true;
+ return;
+ case RawMouseEventType.LeaveWindow:
+ RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, e.Root, e.Position, e.InputModifiers); break;
+ case RawMouseEventType.LeftButtonUp:
+ CheckDraggingAccepted(InputModifiers.LeftMouseButton); break;
+ case RawMouseEventType.MiddleButtonUp:
+ CheckDraggingAccepted(InputModifiers.MiddleMouseButton); break;
+ case RawMouseEventType.RightButtonUp:
+ CheckDraggingAccepted(InputModifiers.RightMouseButton); break;
+ case RawMouseEventType.Move:
+ var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS;
+ if (_initialInputModifiers.Value != mods)
+ {
+ CancelDragging();
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Root != _lastRoot)
+ {
+ if (_lastRoot != null)
+ RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastRoot.PointToClient(e.Root.PointToScreen(e.Position)), e.InputModifiers);
+ RaiseEventAndUpdateCursor(RawDragEventType.DragEnter, e.Root, e.Position, e.InputModifiers);
+ }
+ else
+ RaiseEventAndUpdateCursor(RawDragEventType.DragOver, e.Root, e.Position, e.InputModifiers);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index 5cd3b22fc9..656f3890cd 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -40,6 +40,12 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty PlacementModeProperty =
AvaloniaProperty.Register(nameof(PlacementMode), defaultValue: PlacementMode.Bottom);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ObeyScreenEdgesProperty =
+ AvaloniaProperty.Register(nameof(ObeyScreenEdges));
+
///
/// Defines the property.
///
@@ -136,6 +142,16 @@ namespace Avalonia.Controls.Primitives
set { SetValue(PlacementModeProperty, value); }
}
+ ///
+ /// Gets or sets a value indicating whether the popup positions itself within the nearest screen boundary
+ /// when its opened at a position where it would otherwise overlap the screen edge.
+ ///
+ public bool ObeyScreenEdges
+ {
+ get => GetValue(ObeyScreenEdgesProperty);
+ set => SetValue(ObeyScreenEdgesProperty, value);
+ }
+
///
/// Gets or sets the Horizontal offset of the popup in relation to the
///
@@ -215,7 +231,17 @@ namespace Avalonia.Controls.Primitives
{
var window = _topLevel as Window;
if (window != null)
+ {
window.Deactivated += WindowDeactivated;
+ }
+ else
+ {
+ var parentPopuproot = _topLevel as PopupRoot;
+ if (parentPopuproot != null && parentPopuproot.Parent != null)
+ {
+ ((Popup)(parentPopuproot.Parent)).Closed += ParentClosed;
+ }
+ }
_topLevel.AddHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel);
_nonClientListener = InputManager.Instance.Process.Subscribe(ListenForNonClientClick);
}
@@ -224,6 +250,11 @@ namespace Avalonia.Controls.Primitives
_popupRoot.Show();
+ if (ObeyScreenEdges)
+ {
+ _popupRoot.SnapInsideScreenEdges();
+ }
+
_ignoreIsOpenChanged = true;
IsOpen = true;
_ignoreIsOpenChanged = false;
@@ -244,6 +275,14 @@ namespace Avalonia.Controls.Primitives
var window = _topLevel as Window;
if (window != null)
window.Deactivated -= WindowDeactivated;
+ else
+ {
+ var parentPopuproot = _topLevel as PopupRoot;
+ if (parentPopuproot != null && parentPopuproot.Parent != null)
+ {
+ ((Popup)parentPopuproot.Parent).Closed -= ParentClosed;
+ }
+ }
_nonClientListener?.Dispose();
_nonClientListener = null;
}
@@ -328,8 +367,10 @@ namespace Avalonia.Controls.Primitives
/// The popup's position in screen coordinates.
protected virtual Point GetPosition()
{
- return GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot,
+ var result = GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot,
HorizontalOffset, VerticalOffset);
+
+ return result;
}
internal static Point GetPosition(Control target, PlacementMode placement, PopupRoot popupRoot, double horizontalOffset, double verticalOffset)
@@ -381,9 +422,7 @@ namespace Avalonia.Controls.Primitives
{
if (!StaysOpen)
{
- var root = ((IVisual)e.Source).GetVisualRoot();
-
- if (root != this.PopupRoot)
+ if (!IsChildOrThis((IVisual)e.Source))
{
Close();
e.Handled = true;
@@ -391,6 +430,17 @@ namespace Avalonia.Controls.Primitives
}
}
+ private bool IsChildOrThis(IVisual child)
+ {
+ IVisual root = child.GetVisualRoot();
+ while (root is PopupRoot)
+ {
+ if (root == PopupRoot) return true;
+ root = ((PopupRoot)root).Parent.GetVisualRoot();
+ }
+ return false;
+ }
+
private void WindowDeactivated(object sender, EventArgs e)
{
if (!StaysOpen)
@@ -398,5 +448,13 @@ namespace Avalonia.Controls.Primitives
Close();
}
}
+
+ private void ParentClosed(object sender, EventArgs e)
+ {
+ if (!StaysOpen)
+ {
+ Close();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index 507a085fed..457a7bd4b4 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -2,10 +2,12 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Linq;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Presenters;
using Avalonia.Interactivity;
using Avalonia.Layout;
+using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
@@ -75,6 +77,30 @@ namespace Avalonia.Controls.Primitives
///
public void Dispose() => PlatformImpl?.Dispose();
+ ///
+ /// Moves the Popups position so that it doesnt overlap screen edges.
+ /// This method can be called immediately after Show has been called.
+ ///
+ public void SnapInsideScreenEdges()
+ {
+ var window = this.GetSelfAndLogicalAncestors().OfType().First();
+
+ var screen = window.Screens.ScreenFromPoint(Position);
+
+ var screenX = Position.X + Bounds.Width - screen.Bounds.X;
+ var screenY = Position.Y + Bounds.Height - screen.Bounds.Y;
+
+ if (screenX > screen.Bounds.Width)
+ {
+ Position = Position.WithX(Position.X - (screenX - screen.Bounds.Width));
+ }
+
+ if (screenY > screen.Bounds.Height)
+ {
+ Position = Position.WithY(Position.Y - (screenY - screen.Bounds.Height));
+ }
+ }
+
///
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index c7a77bdf0e..88a9fe077d 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -120,6 +120,7 @@ namespace Avalonia.Controls
.Subscribe(_ =>
{
InvalidateFormattedText();
+ InvalidateMeasure();
});
}
@@ -370,8 +371,6 @@ namespace Avalonia.Controls
_constraint = _formattedText.Constraint;
_formattedText = null;
}
-
- InvalidateMeasure();
}
///
@@ -402,6 +401,7 @@ namespace Avalonia.Controls
{
base.OnAttachedToLogicalTree(e);
InvalidateFormattedText();
+ InvalidateMeasure();
}
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 34c6b1cfd6..890926db54 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -275,8 +275,11 @@ namespace Avalonia.Controls
protected override void OnTextInput(TextInputEventArgs e)
{
- HandleTextInput(e.Text);
- e.Handled = true;
+ if (!e.Handled)
+ {
+ HandleTextInput(e.Text);
+ e.Handled = true;
+ }
}
private void HandleTextInput(string input)
diff --git a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs
index c76555e554..17cf681f15 100644
--- a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs
+++ b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs
@@ -59,7 +59,7 @@ namespace Avalonia.Controls.Utils
public void UpdateLastState()
{
- _states.Last.Value = _host.UndoRedoState;
+ UpdateLastState(_host.UndoRedoState);
}
public void DiscardRedo()
@@ -94,6 +94,7 @@ namespace Avalonia.Controls.Utils
public void Clear()
{
_states.Clear();
+ _currentNode = null;
}
bool WeakTimer.IWeakTimerSubscriber.Tick()
diff --git a/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs b/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
index 2d3f978462..555a0b2354 100644
--- a/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
@@ -86,7 +86,7 @@ namespace Avalonia.Diagnostics.ViewModels
private void UpdateFocusedControl()
{
- _focusedControl = KeyboardDevice.Instance.FocusedElement?.GetType().Name;
+ FocusedControl = KeyboardDevice.Instance.FocusedElement?.GetType().Name;
}
}
}
diff --git a/src/Avalonia.Input/Cursors.cs b/src/Avalonia.Input/Cursors.cs
index e3860e58e5..02a026c998 100644
--- a/src/Avalonia.Input/Cursors.cs
+++ b/src/Avalonia.Input/Cursors.cs
@@ -38,7 +38,10 @@ namespace Avalonia.Input
TopLeftCorner,
TopRightCorner,
BottomLeftCorner,
- BottomRightCorner
+ BottomRightCorner,
+ DragMove,
+ DragCopy,
+ DragLink,
// Not available in GTK directly, see http://www.pixelbeat.org/programming/x_cursors/
// We might enable them later, preferably, by loading pixmax direclty from theme with fallback image
diff --git a/src/Avalonia.Input/DataFormats.cs b/src/Avalonia.Input/DataFormats.cs
new file mode 100644
index 0000000000..559d2cb643
--- /dev/null
+++ b/src/Avalonia.Input/DataFormats.cs
@@ -0,0 +1,15 @@
+namespace Avalonia.Input
+{
+ public static class DataFormats
+ {
+ ///
+ /// Dataformat for plaintext
+ ///
+ public static string Text = nameof(Text);
+
+ ///
+ /// Dataformat for one or more filenames
+ ///
+ public static string FileNames = nameof(FileNames);
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/DataObject.cs b/src/Avalonia.Input/DataObject.cs
new file mode 100644
index 0000000000..cb642f4d65
--- /dev/null
+++ b/src/Avalonia.Input/DataObject.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Avalonia.Input
+{
+ public class DataObject : IDataObject
+ {
+ private readonly Dictionary _items = new Dictionary();
+
+ public bool Contains(string dataFormat)
+ {
+ return _items.ContainsKey(dataFormat);
+ }
+
+ public object Get(string dataFormat)
+ {
+ if (_items.ContainsKey(dataFormat))
+ return _items[dataFormat];
+ return null;
+ }
+
+ public IEnumerable GetDataFormats()
+ {
+ return _items.Keys;
+ }
+
+ public IEnumerable GetFileNames()
+ {
+ return Get(DataFormats.FileNames) as IEnumerable;
+ }
+
+ public string GetText()
+ {
+ return Get(DataFormats.Text) as string;
+ }
+
+ public void Set(string dataFormat, object value)
+ {
+ _items[dataFormat] = value;
+ }
+ }
+}
diff --git a/src/Avalonia.Input/DragDrop.cs b/src/Avalonia.Input/DragDrop.cs
new file mode 100644
index 0000000000..c312732afa
--- /dev/null
+++ b/src/Avalonia.Input/DragDrop.cs
@@ -0,0 +1,54 @@
+using System.Threading.Tasks;
+using Avalonia.Interactivity;
+using Avalonia.Input.Platform;
+
+namespace Avalonia.Input
+{
+ public static class DragDrop
+ {
+ ///
+ /// Event which is raised, when a drag-and-drop operation enters the element.
+ ///
+ public static RoutedEvent DragEnterEvent = RoutedEvent.Register("DragEnter", RoutingStrategies.Bubble, typeof(DragDrop));
+ ///
+ /// Event which is raised, when a drag-and-drop operation leaves the element.
+ ///
+ public static RoutedEvent DragLeaveEvent = RoutedEvent.Register("DragLeave", RoutingStrategies.Bubble, typeof(DragDrop));
+ ///
+ /// Event which is raised, when a drag-and-drop operation is updated while over the element.
+ ///
+ public static RoutedEvent DragOverEvent = RoutedEvent.Register("DragOver", RoutingStrategies.Bubble, typeof(DragDrop));
+ ///
+ /// Event which is raised, when a drag-and-drop operation should complete over the element.
+ ///
+ public static RoutedEvent DropEvent = RoutedEvent.Register("Drop", RoutingStrategies.Bubble, typeof(DragDrop));
+
+ public static AvaloniaProperty AllowDropProperty = AvaloniaProperty.RegisterAttached("AllowDrop", typeof(DragDrop), inherits: true);
+
+ ///
+ /// Gets a value indicating whether the given element can be used as the target of a drag-and-drop operation.
+ ///
+ public static bool GetAllowDrop(Interactive interactive)
+ {
+ return interactive.GetValue(AllowDropProperty);
+ }
+
+ ///
+ /// Sets a value indicating whether the given interactive can be used as the target of a drag-and-drop operation.
+ ///
+ public static void SetAllowDrop(Interactive interactive, bool value)
+ {
+ interactive.SetValue(AllowDropProperty, value);
+ }
+
+ ///
+ /// Starts a dragging operation with the given and returns the applied drop effect from the target.
+ ///
+ ///
+ public static Task DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+ {
+ var src = AvaloniaLocator.Current.GetService();
+ return src?.DoDragDrop(data, allowedEffects) ?? Task.FromResult(DragDropEffects.None);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/DragDropDevice.cs b/src/Avalonia.Input/DragDropDevice.cs
new file mode 100644
index 0000000000..2615e3a212
--- /dev/null
+++ b/src/Avalonia.Input/DragDropDevice.cs
@@ -0,0 +1,111 @@
+using Avalonia.Interactivity;
+using Avalonia.VisualTree;
+using System.Linq;
+using Avalonia.Input.Raw;
+
+namespace Avalonia.Input
+{
+ public class DragDropDevice : IDragDropDevice
+ {
+ public static readonly DragDropDevice Instance = new DragDropDevice();
+
+ private Interactive _lastTarget = null;
+
+ private Interactive GetTarget(IInputElement root, Point local)
+ {
+ var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType()?.FirstOrDefault();
+ if (target != null && DragDrop.GetAllowDrop(target))
+ return target;
+ return null;
+ }
+
+ private DragDropEffects RaiseDragEvent(Interactive target, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data)
+ {
+ if (target == null)
+ return DragDropEffects.None;
+ var args = new DragEventArgs(routedEvent, data)
+ {
+ RoutedEvent = routedEvent,
+ DragEffects = operation
+ };
+ target.RaiseEvent(args);
+ return args.DragEffects;
+ }
+
+ private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+ {
+ _lastTarget = GetTarget(inputRoot, point);
+ return RaiseDragEvent(_lastTarget, DragDrop.DragEnterEvent, effects, data);
+ }
+
+ private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+ {
+ var target = GetTarget(inputRoot, point);
+
+ if (target == _lastTarget)
+ return RaiseDragEvent(target, DragDrop.DragOverEvent, effects, data);
+
+ try
+ {
+ if (_lastTarget != null)
+ _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent));
+ return RaiseDragEvent(target, DragDrop.DragEnterEvent, effects, data);
+ }
+ finally
+ {
+ _lastTarget = target;
+ }
+ }
+
+ private void DragLeave(IInputElement inputRoot)
+ {
+ if (_lastTarget == null)
+ return;
+ try
+ {
+ _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent));
+ }
+ finally
+ {
+ _lastTarget = null;
+ }
+ }
+
+ private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+ {
+ try
+ {
+ return RaiseDragEvent(_lastTarget, DragDrop.DropEvent, effects, data);
+ }
+ finally
+ {
+ _lastTarget = null;
+ }
+ }
+
+ public void ProcessRawEvent(RawInputEventArgs e)
+ {
+ if (!e.Handled && e is RawDragEvent margs)
+ ProcessRawEvent(margs);
+ }
+
+ private void ProcessRawEvent(RawDragEvent e)
+ {
+ switch (e.Type)
+ {
+ case RawDragEventType.DragEnter:
+ e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects);
+ break;
+ case RawDragEventType.DragOver:
+ e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects);
+ break;
+ case RawDragEventType.DragLeave:
+ DragLeave(e.InputRoot);
+ break;
+ case RawDragEventType.Drop:
+ e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects);
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/DragDropEffects.cs b/src/Avalonia.Input/DragDropEffects.cs
new file mode 100644
index 0000000000..bcda1091d5
--- /dev/null
+++ b/src/Avalonia.Input/DragDropEffects.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Avalonia.Input
+{
+ [Flags]
+ public enum DragDropEffects
+ {
+ None = 0,
+ Copy = 1,
+ Move = 2,
+ Link = 4,
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/DragEventArgs.cs b/src/Avalonia.Input/DragEventArgs.cs
new file mode 100644
index 0000000000..12d5a8941e
--- /dev/null
+++ b/src/Avalonia.Input/DragEventArgs.cs
@@ -0,0 +1,18 @@
+using Avalonia.Interactivity;
+
+namespace Avalonia.Input
+{
+ public class DragEventArgs : RoutedEventArgs
+ {
+ public DragDropEffects DragEffects { get; set; }
+
+ public IDataObject Data { get; private set; }
+
+ public DragEventArgs(RoutedEvent routedEvent, IDataObject data)
+ : base(routedEvent)
+ {
+ this.Data = data;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/IDataObject.cs b/src/Avalonia.Input/IDataObject.cs
new file mode 100644
index 0000000000..1b12323d99
--- /dev/null
+++ b/src/Avalonia.Input/IDataObject.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Input
+{
+ ///
+ /// Interface to access information about the data of a drag-and-drop operation.
+ ///
+ public interface IDataObject
+ {
+ ///
+ /// Lists all formats which are present in the DataObject.
+ ///
+ ///
+ IEnumerable GetDataFormats();
+
+ ///
+ /// Checks wether a given DataFormat is present in this object
+ ///
+ ///
+ bool Contains(string dataFormat);
+
+ ///
+ /// Returns the dragged text if the DataObject contains any text.
+ ///
+ ///
+ string GetText();
+
+ ///
+ /// Returns a list of filenames if the DataObject contains filenames.
+ ///
+ ///
+ IEnumerable GetFileNames();
+
+ ///
+ /// Tries to get the data of the given DataFormat.
+ ///
+ object Get(string dataFormat);
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/Platform/IPlatformDragSource.cs b/src/Avalonia.Input/Platform/IPlatformDragSource.cs
new file mode 100644
index 0000000000..669251c50b
--- /dev/null
+++ b/src/Avalonia.Input/Platform/IPlatformDragSource.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+
+namespace Avalonia.Input.Platform
+{
+ public interface IPlatformDragSource
+ {
+ Task DoDragDrop(IDataObject data, DragDropEffects allowedEffects);
+ }
+}
diff --git a/src/Avalonia.Input/Raw/IDragDropDevice.cs b/src/Avalonia.Input/Raw/IDragDropDevice.cs
new file mode 100644
index 0000000000..6aab1b868d
--- /dev/null
+++ b/src/Avalonia.Input/Raw/IDragDropDevice.cs
@@ -0,0 +1,8 @@
+using Avalonia.Input;
+
+namespace Avalonia.Input.Raw
+{
+ public interface IDragDropDevice : IInputDevice
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/Raw/RawDragEvent.cs b/src/Avalonia.Input/Raw/RawDragEvent.cs
new file mode 100644
index 0000000000..49125b4c07
--- /dev/null
+++ b/src/Avalonia.Input/Raw/RawDragEvent.cs
@@ -0,0 +1,26 @@
+using System;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+
+namespace Avalonia.Input.Raw
+{
+ public class RawDragEvent : RawInputEventArgs
+ {
+ public IInputElement InputRoot { get; }
+ public Point Location { get; }
+ public IDataObject Data { get; }
+ public DragDropEffects Effects { get; set; }
+ public RawDragEventType Type { get; }
+
+ public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type,
+ IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects)
+ :base(inputDevice, 0)
+ {
+ Type = type;
+ InputRoot = inputRoot;
+ Location = location;
+ Data = data;
+ Effects = effects;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/Raw/RawDragEventType.cs b/src/Avalonia.Input/Raw/RawDragEventType.cs
new file mode 100644
index 0000000000..9635f77467
--- /dev/null
+++ b/src/Avalonia.Input/Raw/RawDragEventType.cs
@@ -0,0 +1,10 @@
+namespace Avalonia.Input.Raw
+{
+ public enum RawDragEventType
+ {
+ DragEnter,
+ DragOver,
+ DragLeave,
+ Drop
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml
index 66f226d2f6..efb31175fa 100644
--- a/src/Avalonia.Themes.Default/MenuItem.xaml
+++ b/src/Avalonia.Themes.Default/MenuItem.xaml
@@ -45,7 +45,8 @@
+ IsOpen="{TemplateBinding Path=IsSubMenuOpen, Mode=TwoWay}"
+ ObeyScreenEdges="True">
@@ -92,7 +93,8 @@
+ StaysOpen="True"
+ ObeyScreenEdges="True">
diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs
index 4e5cd61994..70804ee04f 100644
--- a/src/Avalonia.Visuals/Matrix.cs
+++ b/src/Avalonia.Visuals/Matrix.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -317,23 +318,16 @@ namespace Avalonia
/// The .
public static Matrix Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToArray();
-
- if (parts.Length == 6)
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Matrix"))
{
return new Matrix(
- double.Parse(parts[0], culture),
- double.Parse(parts[1], culture),
- double.Parse(parts[2], culture),
- double.Parse(parts[3], culture),
- double.Parse(parts[4], culture),
- double.Parse(parts[5], culture));
- }
- else
- {
- throw new FormatException("Invalid Matrix.");
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble()
+ );
}
}
}
diff --git a/src/Avalonia.Visuals/Media/Brush.cs b/src/Avalonia.Visuals/Media/Brush.cs
index 40ac24b605..d6b0e43cdc 100644
--- a/src/Avalonia.Visuals/Media/Brush.cs
+++ b/src/Avalonia.Visuals/Media/Brush.cs
@@ -34,26 +34,21 @@ namespace Avalonia.Media
/// The .
public static IBrush Parse(string s)
{
+ Contract.Requires(s != null);
+ Contract.Requires(s.Length > 0);
+
if (s[0] == '#')
{
return new SolidColorBrush(Color.Parse(s));
}
- else
- {
- var upper = s.ToUpperInvariant();
- var member = typeof(Brushes).GetTypeInfo().DeclaredProperties
- .FirstOrDefault(x => x.Name.ToUpperInvariant() == upper);
- if (member != null)
- {
- var brush = (ISolidColorBrush)member.GetValue(null);
- return new SolidColorBrush(brush.Color, brush.Opacity);
- }
- else
- {
- throw new FormatException($"Invalid brush string: '{s}'.");
- }
+ var brush = KnownColors.GetKnownBrush(s);
+ if (brush != null)
+ {
+ return brush;
}
+
+ throw new FormatException($"Invalid brush string: '{s}'.");
}
}
}
diff --git a/src/Avalonia.Visuals/Media/Brushes.cs b/src/Avalonia.Visuals/Media/Brushes.cs
index 4c89c97b49..83ff043397 100644
--- a/src/Avalonia.Visuals/Media/Brushes.cs
+++ b/src/Avalonia.Visuals/Media/Brushes.cs
@@ -1,8 +1,6 @@
// 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 Avalonia.Media.Immutable;
-
namespace Avalonia.Media
{
///
@@ -10,857 +8,709 @@ namespace Avalonia.Media
///
public static class Brushes
{
- ///
- /// Initializes static members of the class.
- ///
- static Brushes()
- {
- AliceBlue = new ImmutableSolidColorBrush(Colors.AliceBlue);
- AntiqueWhite = new ImmutableSolidColorBrush(Colors.AntiqueWhite);
- Aqua = new ImmutableSolidColorBrush(Colors.Aqua);
- Aquamarine = new ImmutableSolidColorBrush(Colors.Aquamarine);
- Azure = new ImmutableSolidColorBrush(Colors.Azure);
- Beige = new ImmutableSolidColorBrush(Colors.Beige);
- Bisque = new ImmutableSolidColorBrush(Colors.Bisque);
- Black = new ImmutableSolidColorBrush(Colors.Black);
- BlanchedAlmond = new ImmutableSolidColorBrush(Colors.BlanchedAlmond);
- Blue = new ImmutableSolidColorBrush(Colors.Blue);
- BlueViolet = new ImmutableSolidColorBrush(Colors.BlueViolet);
- Brown = new ImmutableSolidColorBrush(Colors.Brown);
- BurlyWood = new ImmutableSolidColorBrush(Colors.BurlyWood);
- CadetBlue = new ImmutableSolidColorBrush(Colors.CadetBlue);
- Chartreuse = new ImmutableSolidColorBrush(Colors.Chartreuse);
- Chocolate = new ImmutableSolidColorBrush(Colors.Chocolate);
- Coral = new ImmutableSolidColorBrush(Colors.Coral);
- CornflowerBlue = new ImmutableSolidColorBrush(Colors.CornflowerBlue);
- Cornsilk = new ImmutableSolidColorBrush(Colors.Cornsilk);
- Crimson = new ImmutableSolidColorBrush(Colors.Crimson);
- Cyan = new ImmutableSolidColorBrush(Colors.Cyan);
- DarkBlue = new ImmutableSolidColorBrush(Colors.DarkBlue);
- DarkCyan = new ImmutableSolidColorBrush(Colors.DarkCyan);
- DarkGoldenrod = new ImmutableSolidColorBrush(Colors.DarkGoldenrod);
- DarkGray = new ImmutableSolidColorBrush(Colors.DarkGray);
- DarkGreen = new ImmutableSolidColorBrush(Colors.DarkGreen);
- DarkKhaki = new ImmutableSolidColorBrush(Colors.DarkKhaki);
- DarkMagenta = new ImmutableSolidColorBrush(Colors.DarkMagenta);
- DarkOliveGreen = new ImmutableSolidColorBrush(Colors.DarkOliveGreen);
- DarkOrange = new ImmutableSolidColorBrush(Colors.DarkOrange);
- DarkOrchid = new ImmutableSolidColorBrush(Colors.DarkOrchid);
- DarkRed = new ImmutableSolidColorBrush(Colors.DarkRed);
- DarkSalmon = new ImmutableSolidColorBrush(Colors.DarkSalmon);
- DarkSeaGreen = new ImmutableSolidColorBrush(Colors.DarkSeaGreen);
- DarkSlateBlue = new ImmutableSolidColorBrush(Colors.DarkSlateBlue);
- DarkSlateGray = new ImmutableSolidColorBrush(Colors.DarkSlateGray);
- DarkTurquoise = new ImmutableSolidColorBrush(Colors.DarkTurquoise);
- DarkViolet = new ImmutableSolidColorBrush(Colors.DarkViolet);
- DeepPink = new ImmutableSolidColorBrush(Colors.DeepPink);
- DeepSkyBlue = new ImmutableSolidColorBrush(Colors.DeepSkyBlue);
- DimGray = new ImmutableSolidColorBrush(Colors.DimGray);
- DodgerBlue = new ImmutableSolidColorBrush(Colors.DodgerBlue);
- Firebrick = new ImmutableSolidColorBrush(Colors.Firebrick);
- FloralWhite = new ImmutableSolidColorBrush(Colors.FloralWhite);
- ForestGreen = new ImmutableSolidColorBrush(Colors.ForestGreen);
- Fuchsia = new ImmutableSolidColorBrush(Colors.Fuchsia);
- Gainsboro = new ImmutableSolidColorBrush(Colors.Gainsboro);
- GhostWhite = new ImmutableSolidColorBrush(Colors.GhostWhite);
- Gold = new ImmutableSolidColorBrush(Colors.Gold);
- Goldenrod = new ImmutableSolidColorBrush(Colors.Goldenrod);
- Gray = new ImmutableSolidColorBrush(Colors.Gray);
- Green = new ImmutableSolidColorBrush(Colors.Green);
- GreenYellow = new ImmutableSolidColorBrush(Colors.GreenYellow);
- Honeydew = new ImmutableSolidColorBrush(Colors.Honeydew);
- HotPink = new ImmutableSolidColorBrush(Colors.HotPink);
- IndianRed = new ImmutableSolidColorBrush(Colors.IndianRed);
- Indigo = new ImmutableSolidColorBrush(Colors.Indigo);
- Ivory = new ImmutableSolidColorBrush(Colors.Ivory);
- Khaki = new ImmutableSolidColorBrush(Colors.Khaki);
- Lavender = new ImmutableSolidColorBrush(Colors.Lavender);
- LavenderBlush = new ImmutableSolidColorBrush(Colors.LavenderBlush);
- LawnGreen = new ImmutableSolidColorBrush(Colors.LawnGreen);
- LemonChiffon = new ImmutableSolidColorBrush(Colors.LemonChiffon);
- LightBlue = new ImmutableSolidColorBrush(Colors.LightBlue);
- LightCoral = new ImmutableSolidColorBrush(Colors.LightCoral);
- LightCyan = new ImmutableSolidColorBrush(Colors.LightCyan);
- LightGoldenrodYellow = new ImmutableSolidColorBrush(Colors.LightGoldenrodYellow);
- LightGray = new ImmutableSolidColorBrush(Colors.LightGray);
- LightGreen = new ImmutableSolidColorBrush(Colors.LightGreen);
- LightPink = new ImmutableSolidColorBrush(Colors.LightPink);
- LightSalmon = new ImmutableSolidColorBrush(Colors.LightSalmon);
- LightSeaGreen = new ImmutableSolidColorBrush(Colors.LightSeaGreen);
- LightSkyBlue = new ImmutableSolidColorBrush(Colors.LightSkyBlue);
- LightSlateGray = new ImmutableSolidColorBrush(Colors.LightSlateGray);
- LightSteelBlue = new ImmutableSolidColorBrush(Colors.LightSteelBlue);
- LightYellow = new ImmutableSolidColorBrush(Colors.LightYellow);
- Lime = new ImmutableSolidColorBrush(Colors.Lime);
- LimeGreen = new ImmutableSolidColorBrush(Colors.LimeGreen);
- Linen = new ImmutableSolidColorBrush(Colors.Linen);
- Magenta = new ImmutableSolidColorBrush(Colors.Magenta);
- Maroon = new ImmutableSolidColorBrush(Colors.Maroon);
- MediumAquamarine = new ImmutableSolidColorBrush(Colors.MediumAquamarine);
- MediumBlue = new ImmutableSolidColorBrush(Colors.MediumBlue);
- MediumOrchid = new ImmutableSolidColorBrush(Colors.MediumOrchid);
- MediumPurple = new ImmutableSolidColorBrush(Colors.MediumPurple);
- MediumSeaGreen = new ImmutableSolidColorBrush(Colors.MediumSeaGreen);
- MediumSlateBlue = new ImmutableSolidColorBrush(Colors.MediumSlateBlue);
- MediumSpringGreen = new ImmutableSolidColorBrush(Colors.MediumSpringGreen);
- MediumTurquoise = new ImmutableSolidColorBrush(Colors.MediumTurquoise);
- MediumVioletRed = new ImmutableSolidColorBrush(Colors.MediumVioletRed);
- MidnightBlue = new ImmutableSolidColorBrush(Colors.MidnightBlue);
- MintCream = new ImmutableSolidColorBrush(Colors.MintCream);
- MistyRose = new ImmutableSolidColorBrush(Colors.MistyRose);
- Moccasin = new ImmutableSolidColorBrush(Colors.Moccasin);
- NavajoWhite = new ImmutableSolidColorBrush(Colors.NavajoWhite);
- Navy = new ImmutableSolidColorBrush(Colors.Navy);
- OldLace = new ImmutableSolidColorBrush(Colors.OldLace);
- Olive = new ImmutableSolidColorBrush(Colors.Olive);
- OliveDrab = new ImmutableSolidColorBrush(Colors.OliveDrab);
- Orange = new ImmutableSolidColorBrush(Colors.Orange);
- OrangeRed = new ImmutableSolidColorBrush(Colors.OrangeRed);
- Orchid = new ImmutableSolidColorBrush(Colors.Orchid);
- PaleGoldenrod = new ImmutableSolidColorBrush(Colors.PaleGoldenrod);
- PaleGreen = new ImmutableSolidColorBrush(Colors.PaleGreen);
- PaleTurquoise = new ImmutableSolidColorBrush(Colors.PaleTurquoise);
- PaleVioletRed = new ImmutableSolidColorBrush(Colors.PaleVioletRed);
- PapayaWhip = new ImmutableSolidColorBrush(Colors.PapayaWhip);
- PeachPuff = new ImmutableSolidColorBrush(Colors.PeachPuff);
- Peru = new ImmutableSolidColorBrush(Colors.Peru);
- Pink = new ImmutableSolidColorBrush(Colors.Pink);
- Plum = new ImmutableSolidColorBrush(Colors.Plum);
- PowderBlue = new ImmutableSolidColorBrush(Colors.PowderBlue);
- Purple = new ImmutableSolidColorBrush(Colors.Purple);
- Red = new ImmutableSolidColorBrush(Colors.Red);
- RosyBrown = new ImmutableSolidColorBrush(Colors.RosyBrown);
- RoyalBlue = new ImmutableSolidColorBrush(Colors.RoyalBlue);
- SaddleBrown = new ImmutableSolidColorBrush(Colors.SaddleBrown);
- Salmon = new ImmutableSolidColorBrush(Colors.Salmon);
- SandyBrown = new ImmutableSolidColorBrush(Colors.SandyBrown);
- SeaGreen = new ImmutableSolidColorBrush(Colors.SeaGreen);
- SeaShell = new ImmutableSolidColorBrush(Colors.SeaShell);
- Sienna = new ImmutableSolidColorBrush(Colors.Sienna);
- Silver = new ImmutableSolidColorBrush(Colors.Silver);
- SkyBlue = new ImmutableSolidColorBrush(Colors.SkyBlue);
- SlateBlue = new ImmutableSolidColorBrush(Colors.SlateBlue);
- SlateGray = new ImmutableSolidColorBrush(Colors.SlateGray);
- Snow = new ImmutableSolidColorBrush(Colors.Snow);
- SpringGreen = new ImmutableSolidColorBrush(Colors.SpringGreen);
- SteelBlue = new ImmutableSolidColorBrush(Colors.SteelBlue);
- Tan = new ImmutableSolidColorBrush(Colors.Tan);
- Teal = new ImmutableSolidColorBrush(Colors.Teal);
- Thistle = new ImmutableSolidColorBrush(Colors.Thistle);
- Tomato = new ImmutableSolidColorBrush(Colors.Tomato);
- Transparent = new ImmutableSolidColorBrush(Colors.Transparent);
- Turquoise = new ImmutableSolidColorBrush(Colors.Turquoise);
- Violet = new ImmutableSolidColorBrush(Colors.Violet);
- Wheat = new ImmutableSolidColorBrush(Colors.Wheat);
- White = new ImmutableSolidColorBrush(Colors.White);
- WhiteSmoke = new ImmutableSolidColorBrush(Colors.WhiteSmoke);
- Yellow = new ImmutableSolidColorBrush(Colors.Yellow);
- YellowGreen = new ImmutableSolidColorBrush(Colors.YellowGreen);
- }
-
///
/// Gets an colored brush.
///
- public static ISolidColorBrush AliceBlue { get; private set; }
+ public static ISolidColorBrush AliceBlue => KnownColor.AliceBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush AntiqueWhite { get; private set; }
+ public static ISolidColorBrush AntiqueWhite => KnownColor.AntiqueWhite.ToBrush();
///
- /// Gets an colored brush.
+ /// Gets an colored brush.
///
- public static ISolidColorBrush Aqua { get; private set; }
+ public static ISolidColorBrush Aqua => KnownColor.Aqua.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Aquamarine { get; private set; }
+ public static ISolidColorBrush Aquamarine => KnownColor.Aquamarine.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Azure { get; private set; }
+ public static ISolidColorBrush Azure => KnownColor.Azure.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Beige { get; private set; }
+ public static ISolidColorBrush Beige => KnownColor.Beige.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Bisque { get; private set; }
+ public static ISolidColorBrush Bisque => KnownColor.Bisque.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Black { get; private set; }
+ public static ISolidColorBrush Black => KnownColor.Black.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush BlanchedAlmond { get; private set; }
+ public static ISolidColorBrush BlanchedAlmond => KnownColor.BlanchedAlmond.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Blue { get; private set; }
+ public static ISolidColorBrush Blue => KnownColor.Blue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush BlueViolet { get; private set; }
+ public static ISolidColorBrush BlueViolet => KnownColor.BlueViolet.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Brown { get; private set; }
+ public static ISolidColorBrush Brown => KnownColor.Brown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush BurlyWood { get; private set; }
+ public static ISolidColorBrush BurlyWood => KnownColor.BurlyWood.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush CadetBlue { get; private set; }
+ public static ISolidColorBrush CadetBlue => KnownColor.CadetBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Chartreuse { get; private set; }
+ public static ISolidColorBrush Chartreuse => KnownColor.Chartreuse.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Chocolate { get; private set; }
+ public static ISolidColorBrush Chocolate => KnownColor.Chocolate.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Coral { get; private set; }
+ public static ISolidColorBrush Coral => KnownColor.Coral.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush CornflowerBlue { get; private set; }
+ public static ISolidColorBrush CornflowerBlue => KnownColor.CornflowerBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Cornsilk { get; private set; }
+ public static ISolidColorBrush Cornsilk => KnownColor.Cornsilk.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Crimson { get; private set; }
+ public static ISolidColorBrush Crimson => KnownColor.Crimson.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Cyan { get; private set; }
+ public static ISolidColorBrush Cyan => KnownColor.Cyan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkBlue { get; private set; }
+ public static ISolidColorBrush DarkBlue => KnownColor.DarkBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkCyan { get; private set; }
+ public static ISolidColorBrush DarkCyan => KnownColor.DarkCyan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkGoldenrod { get; private set; }
+ public static ISolidColorBrush DarkGoldenrod => KnownColor.DarkGoldenrod.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkGray { get; private set; }
+ public static ISolidColorBrush DarkGray => KnownColor.DarkGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkGreen { get; private set; }
+ public static ISolidColorBrush DarkGreen => KnownColor.DarkGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkKhaki { get; private set; }
+ public static ISolidColorBrush DarkKhaki => KnownColor.DarkKhaki.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkMagenta { get; private set; }
+ public static ISolidColorBrush DarkMagenta => KnownColor.DarkMagenta.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkOliveGreen { get; private set; }
+ public static ISolidColorBrush DarkOliveGreen => KnownColor.DarkOliveGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkOrange { get; private set; }
+ public static ISolidColorBrush DarkOrange => KnownColor.DarkOrange.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkOrchid { get; private set; }
+ public static ISolidColorBrush DarkOrchid => KnownColor.DarkOrchid.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkRed { get; private set; }
+ public static ISolidColorBrush DarkRed => KnownColor.DarkRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSalmon { get; private set; }
+ public static ISolidColorBrush DarkSalmon => KnownColor.DarkSalmon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSeaGreen { get; private set; }
+ public static ISolidColorBrush DarkSeaGreen => KnownColor.DarkSeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSlateBlue { get; private set; }
+ public static ISolidColorBrush DarkSlateBlue => KnownColor.DarkSlateBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSlateGray { get; private set; }
+ public static ISolidColorBrush DarkSlateGray => KnownColor.DarkSlateGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkTurquoise { get; private set; }
+ public static ISolidColorBrush DarkTurquoise => KnownColor.DarkTurquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkViolet { get; private set; }
+ public static ISolidColorBrush DarkViolet => KnownColor.DarkViolet.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DeepPink { get; private set; }
+ public static ISolidColorBrush DeepPink => KnownColor.DeepPink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DeepSkyBlue { get; private set; }
+ public static ISolidColorBrush DeepSkyBlue => KnownColor.DeepSkyBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DimGray { get; private set; }
+ public static ISolidColorBrush DimGray => KnownColor.DimGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DodgerBlue { get; private set; }
+ public static ISolidColorBrush DodgerBlue => KnownColor.DodgerBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Firebrick { get; private set; }
+ public static ISolidColorBrush Firebrick => KnownColor.Firebrick.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush FloralWhite { get; private set; }
+ public static ISolidColorBrush FloralWhite => KnownColor.FloralWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush ForestGreen { get; private set; }
+ public static ISolidColorBrush ForestGreen => KnownColor.ForestGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Fuchsia { get; private set; }
+ public static ISolidColorBrush Fuchsia => KnownColor.Fuchsia.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Gainsboro { get; private set; }
+ public static ISolidColorBrush Gainsboro => KnownColor.Gainsboro.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush GhostWhite { get; private set; }
+ public static ISolidColorBrush GhostWhite => KnownColor.GhostWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Gold { get; private set; }
+ public static ISolidColorBrush Gold => KnownColor.Gold.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Goldenrod { get; private set; }
+ public static ISolidColorBrush Goldenrod => KnownColor.Goldenrod.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Gray { get; private set; }
+ public static ISolidColorBrush Gray => KnownColor.Gray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Green { get; private set; }
+ public static ISolidColorBrush Green => KnownColor.Green.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush GreenYellow { get; private set; }
+ public static ISolidColorBrush GreenYellow => KnownColor.GreenYellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Honeydew { get; private set; }
+ public static ISolidColorBrush Honeydew => KnownColor.Honeydew.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush HotPink { get; private set; }
+ public static ISolidColorBrush HotPink => KnownColor.HotPink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush IndianRed { get; private set; }
+ public static ISolidColorBrush IndianRed => KnownColor.IndianRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Indigo { get; private set; }
+ public static ISolidColorBrush Indigo => KnownColor.Indigo.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Ivory { get; private set; }
+ public static ISolidColorBrush Ivory => KnownColor.Ivory.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Khaki { get; private set; }
+ public static ISolidColorBrush Khaki => KnownColor.Khaki.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Lavender { get; private set; }
+ public static ISolidColorBrush Lavender => KnownColor.Lavender.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LavenderBlush { get; private set; }
+ public static ISolidColorBrush LavenderBlush => KnownColor.LavenderBlush.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LawnGreen { get; private set; }
+ public static ISolidColorBrush LawnGreen => KnownColor.LawnGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LemonChiffon { get; private set; }
+ public static ISolidColorBrush LemonChiffon => KnownColor.LemonChiffon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightBlue { get; private set; }
+ public static ISolidColorBrush LightBlue => KnownColor.LightBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightCoral { get; private set; }
+ public static ISolidColorBrush LightCoral => KnownColor.LightCoral.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightCyan { get; private set; }
+ public static ISolidColorBrush LightCyan => KnownColor.LightCyan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightGoldenrodYellow { get; private set; }
+ public static ISolidColorBrush LightGoldenrodYellow => KnownColor.LightGoldenrodYellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightGray { get; private set; }
+ public static ISolidColorBrush LightGray => KnownColor.LightGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightGreen { get; private set; }
+ public static ISolidColorBrush LightGreen => KnownColor.LightGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightPink { get; private set; }
+ public static ISolidColorBrush LightPink => KnownColor.LightPink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSalmon { get; private set; }
+ public static ISolidColorBrush LightSalmon => KnownColor.LightSalmon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSeaGreen { get; private set; }
+ public static ISolidColorBrush LightSeaGreen => KnownColor.LightSeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSkyBlue { get; private set; }
+ public static ISolidColorBrush LightSkyBlue => KnownColor.LightSkyBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSlateGray { get; private set; }
+ public static ISolidColorBrush LightSlateGray => KnownColor.LightSlateGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSteelBlue { get; private set; }
+ public static ISolidColorBrush LightSteelBlue => KnownColor.LightSteelBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightYellow { get; private set; }
+ public static ISolidColorBrush LightYellow => KnownColor.LightYellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Lime { get; private set; }
+ public static ISolidColorBrush Lime => KnownColor.Lime.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LimeGreen { get; private set; }
+ public static ISolidColorBrush LimeGreen => KnownColor.LimeGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Linen { get; private set; }
+ public static ISolidColorBrush Linen => KnownColor.Linen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Magenta { get; private set; }
+ public static ISolidColorBrush Magenta => KnownColor.Magenta.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Maroon { get; private set; }
+ public static ISolidColorBrush Maroon => KnownColor.Maroon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumAquamarine { get; private set; }
+ public static ISolidColorBrush MediumAquamarine => KnownColor.MediumAquamarine.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumBlue { get; private set; }
+ public static ISolidColorBrush MediumBlue => KnownColor.MediumBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumOrchid { get; private set; }
+ public static ISolidColorBrush MediumOrchid => KnownColor.MediumOrchid.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumPurple { get; private set; }
+ public static ISolidColorBrush MediumPurple => KnownColor.MediumPurple.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumSeaGreen { get; private set; }
+ public static ISolidColorBrush MediumSeaGreen => KnownColor.MediumSeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumSlateBlue { get; private set; }
+ public static ISolidColorBrush MediumSlateBlue => KnownColor.MediumSlateBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumSpringGreen { get; private set; }
+ public static ISolidColorBrush MediumSpringGreen => KnownColor.MediumSpringGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumTurquoise { get; private set; }
+ public static ISolidColorBrush MediumTurquoise => KnownColor.MediumTurquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumVioletRed { get; private set; }
+ public static ISolidColorBrush MediumVioletRed => KnownColor.MediumVioletRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MidnightBlue { get; private set; }
+ public static ISolidColorBrush MidnightBlue => KnownColor.MidnightBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MintCream { get; private set; }
+ public static ISolidColorBrush MintCream => KnownColor.MintCream.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MistyRose { get; private set; }
+ public static ISolidColorBrush MistyRose => KnownColor.MistyRose.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Moccasin { get; private set; }
+ public static ISolidColorBrush Moccasin => KnownColor.Moccasin.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush NavajoWhite { get; private set; }
+ public static ISolidColorBrush NavajoWhite => KnownColor.NavajoWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Navy { get; private set; }
+ public static ISolidColorBrush Navy => KnownColor.Navy.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush OldLace { get; private set; }
+ public static ISolidColorBrush OldLace => KnownColor.OldLace.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Olive { get; private set; }
+ public static ISolidColorBrush Olive => KnownColor.Olive.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush OliveDrab { get; private set; }
+ public static ISolidColorBrush OliveDrab => KnownColor.OliveDrab.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Orange { get; private set; }
+ public static ISolidColorBrush Orange => KnownColor.Orange.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush OrangeRed { get; private set; }
+ public static ISolidColorBrush OrangeRed => KnownColor.OrangeRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Orchid { get; private set; }
+ public static ISolidColorBrush Orchid => KnownColor.Orchid.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleGoldenrod { get; private set; }
+ public static ISolidColorBrush PaleGoldenrod => KnownColor.PaleGoldenrod.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleGreen { get; private set; }
+ public static ISolidColorBrush PaleGreen => KnownColor.PaleGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleTurquoise { get; private set; }
+ public static ISolidColorBrush PaleTurquoise => KnownColor.PaleTurquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleVioletRed { get; private set; }
+ public static ISolidColorBrush PaleVioletRed => KnownColor.PaleVioletRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PapayaWhip { get; private set; }
+ public static ISolidColorBrush PapayaWhip => KnownColor.PapayaWhip.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PeachPuff { get; private set; }
+ public static ISolidColorBrush PeachPuff => KnownColor.PeachPuff.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Peru { get; private set; }
+ public static ISolidColorBrush Peru => KnownColor.Peru.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Pink { get; private set; }
+ public static ISolidColorBrush Pink => KnownColor.Pink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Plum { get; private set; }
+ public static ISolidColorBrush Plum => KnownColor.Plum.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PowderBlue { get; private set; }
+ public static ISolidColorBrush PowderBlue => KnownColor.PowderBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Purple { get; private set; }
+ public static ISolidColorBrush Purple => KnownColor.Purple.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Red { get; private set; }
+ public static ISolidColorBrush Red => KnownColor.Red.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush RosyBrown { get; private set; }
+ public static ISolidColorBrush RosyBrown => KnownColor.RosyBrown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush RoyalBlue { get; private set; }
+ public static ISolidColorBrush RoyalBlue => KnownColor.RoyalBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SaddleBrown { get; private set; }
+ public static ISolidColorBrush SaddleBrown => KnownColor.SaddleBrown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Salmon { get; private set; }
+ public static ISolidColorBrush Salmon => KnownColor.Salmon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SandyBrown { get; private set; }
+ public static ISolidColorBrush SandyBrown => KnownColor.SandyBrown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SeaGreen { get; private set; }
+ public static ISolidColorBrush SeaGreen => KnownColor.SeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SeaShell { get; private set; }
+ public static ISolidColorBrush SeaShell => KnownColor.SeaShell.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Sienna { get; private set; }
+ public static ISolidColorBrush Sienna => KnownColor.Sienna.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Silver { get; private set; }
+ public static ISolidColorBrush Silver => KnownColor.Silver.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SkyBlue { get; private set; }
+ public static ISolidColorBrush SkyBlue => KnownColor.SkyBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SlateBlue { get; private set; }
+ public static ISolidColorBrush SlateBlue => KnownColor.SlateBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SlateGray { get; private set; }
+ public static ISolidColorBrush SlateGray => KnownColor.SlateGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Snow { get; private set; }
+ public static ISolidColorBrush Snow => KnownColor.Snow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SpringGreen { get; private set; }
+ public static ISolidColorBrush SpringGreen => KnownColor.SpringGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SteelBlue { get; private set; }
+ public static ISolidColorBrush SteelBlue => KnownColor.SteelBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Tan { get; private set; }
+ public static ISolidColorBrush Tan => KnownColor.Tan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Teal { get; private set; }
+ public static ISolidColorBrush Teal => KnownColor.Teal.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Thistle { get; private set; }
+ public static ISolidColorBrush Thistle => KnownColor.Thistle.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Tomato { get; private set; }
+ public static ISolidColorBrush Tomato => KnownColor.Tomato.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Transparent { get; private set; }
+ public static ISolidColorBrush Transparent => KnownColor.Transparent.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Turquoise { get; private set; }
+ public static ISolidColorBrush Turquoise => KnownColor.Turquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Violet { get; private set; }
+ public static ISolidColorBrush Violet => KnownColor.Violet.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Wheat { get; private set; }
+ public static ISolidColorBrush Wheat => KnownColor.Wheat.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush White { get; private set; }
+ public static ISolidColorBrush White => KnownColor.White.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush WhiteSmoke { get; private set; }
+ public static ISolidColorBrush WhiteSmoke => KnownColor.WhiteSmoke.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Yellow { get; private set; }
+ public static ISolidColorBrush Yellow => KnownColor.Yellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush YellowGreen { get; private set; }
+ public static ISolidColorBrush YellowGreen => KnownColor.YellowGreen.ToBrush();
}
}
diff --git a/src/Avalonia.Visuals/Media/Color.cs b/src/Avalonia.Visuals/Media/Color.cs
index cbf5a86fd6..82cc19347a 100644
--- a/src/Avalonia.Visuals/Media/Color.cs
+++ b/src/Avalonia.Visuals/Media/Color.cs
@@ -88,6 +88,9 @@ namespace Avalonia.Media
/// The .
public static Color Parse(string s)
{
+ if (s == null) throw new ArgumentNullException(nameof(s));
+ if (s.Length == 0) throw new FormatException();
+
if (s[0] == '#')
{
var or = 0u;
@@ -103,21 +106,15 @@ namespace Avalonia.Media
return FromUInt32(uint.Parse(s.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture) | or);
}
- else
- {
- var upper = s.ToUpperInvariant();
- var member = typeof(Colors).GetTypeInfo().DeclaredProperties
- .FirstOrDefault(x => x.Name.ToUpperInvariant() == upper);
- if (member != null)
- {
- return (Color)member.GetValue(null);
- }
- else
- {
- throw new FormatException($"Invalid color string: '{s}'.");
- }
+ var knownColor = KnownColors.GetKnownColor(s);
+
+ if (knownColor != KnownColor.None)
+ {
+ return knownColor.ToColor();
}
+
+ throw new FormatException($"Invalid color string: '{s}'.");
}
///
@@ -128,8 +125,8 @@ namespace Avalonia.Media
///
public override string ToString()
{
- uint rgb = ((uint)A << 24) | ((uint)R << 16) | ((uint)G << 8) | (uint)B;
- return $"#{rgb:x8}";
+ uint rgb = ToUint32();
+ return KnownColors.GetKnownColorName(rgb) ?? $"#{rgb:x8}";
}
///
diff --git a/src/Avalonia.Visuals/Media/Colors.cs b/src/Avalonia.Visuals/Media/Colors.cs
index 7296d7dd39..1067cf66aa 100644
--- a/src/Avalonia.Visuals/Media/Colors.cs
+++ b/src/Avalonia.Visuals/Media/Colors.cs
@@ -1,6 +1,8 @@
// 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.Linq;
+
namespace Avalonia.Media
{
///
@@ -11,706 +13,706 @@ namespace Avalonia.Media
///
/// Gets a color with an ARGB value of #fff0f8ff.
///
- public static Color AliceBlue => Color.FromUInt32(0xfff0f8ff);
+ public static Color AliceBlue => KnownColor.AliceBlue.ToColor();
///
/// Gets a color with an ARGB value of #fffaebd7.
///
- public static Color AntiqueWhite => Color.FromUInt32(0xfffaebd7);
+ public static Color AntiqueWhite => KnownColor.AntiqueWhite.ToColor();
///
/// Gets a color with an ARGB value of #ff00ffff.
///
- public static Color Aqua => Color.FromUInt32(0xff00ffff);
+ public static Color Aqua => KnownColor.Aqua.ToColor();
///
/// Gets a color with an ARGB value of #ff7fffd4.
///
- public static Color Aquamarine => Color.FromUInt32(0xff7fffd4);
+ public static Color Aquamarine => KnownColor.Aquamarine.ToColor();
///
/// Gets a color with an ARGB value of #fff0ffff.
///
- public static Color Azure => Color.FromUInt32(0xfff0ffff);
+ public static Color Azure => KnownColor.Azure.ToColor();
///
/// Gets a color with an ARGB value of #fff5f5dc.
///
- public static Color Beige => Color.FromUInt32(0xfff5f5dc);
+ public static Color Beige => KnownColor.Beige.ToColor();
///
/// Gets a color with an ARGB value of #ffffe4c4.
///
- public static Color Bisque => Color.FromUInt32(0xffffe4c4);
+ public static Color Bisque => KnownColor.Bisque.ToColor();
///
/// Gets a color with an ARGB value of #ff000000.
///
- public static Color Black => Color.FromUInt32(0xff000000);
+ public static Color Black => KnownColor.Black.ToColor();
///
/// Gets a color with an ARGB value of #ffffebcd.
///
- public static Color BlanchedAlmond => Color.FromUInt32(0xffffebcd);
+ public static Color BlanchedAlmond => KnownColor.BlanchedAlmond.ToColor();
///
/// Gets a color with an ARGB value of #ff0000ff.
///
- public static Color Blue => Color.FromUInt32(0xff0000ff);
+ public static Color Blue => KnownColor.Blue.ToColor();
///
/// Gets a color with an ARGB value of #ff8a2be2.
///
- public static Color BlueViolet => Color.FromUInt32(0xff8a2be2);
+ public static Color BlueViolet => KnownColor.BlueViolet.ToColor();
///
/// Gets a color with an ARGB value of #ffa52a2a.
///
- public static Color Brown => Color.FromUInt32(0xffa52a2a);
+ public static Color Brown => KnownColor.Brown.ToColor();
///
/// Gets a color with an ARGB value of #ffdeb887.
///
- public static Color BurlyWood => Color.FromUInt32(0xffdeb887);
+ public static Color BurlyWood => KnownColor.BurlyWood.ToColor();
///
/// Gets a color with an ARGB value of #ff5f9ea0.
///
- public static Color CadetBlue => Color.FromUInt32(0xff5f9ea0);
+ public static Color CadetBlue => KnownColor.CadetBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff7fff00.
///
- public static Color Chartreuse => Color.FromUInt32(0xff7fff00);
+ public static Color Chartreuse => KnownColor.Chartreuse.ToColor();
///
/// Gets a color with an ARGB value of #ffd2691e.
///
- public static Color Chocolate => Color.FromUInt32(0xffd2691e);
+ public static Color Chocolate => KnownColor.Chocolate.ToColor();
///
/// Gets a color with an ARGB value of #ffff7f50.
///
- public static Color Coral => Color.FromUInt32(0xffff7f50);
+ public static Color Coral => KnownColor.Coral.ToColor();
///
/// Gets a color with an ARGB value of #ff6495ed.
///
- public static Color CornflowerBlue => Color.FromUInt32(0xff6495ed);
+ public static Color CornflowerBlue => KnownColor.CornflowerBlue.ToColor();
///
/// Gets a color with an ARGB value of #fffff8dc.
///
- public static Color Cornsilk => Color.FromUInt32(0xfffff8dc);
+ public static Color Cornsilk => KnownColor.Cornsilk.ToColor();
///
/// Gets a color with an ARGB value of #ffdc143c.
///
- public static Color Crimson => Color.FromUInt32(0xffdc143c);
+ public static Color Crimson => KnownColor.Crimson.ToColor();
///
/// Gets a color with an ARGB value of #ff00ffff.
///
- public static Color Cyan => Color.FromUInt32(0xff00ffff);
+ public static Color Cyan => KnownColor.Cyan.ToColor();
///
/// Gets a color with an ARGB value of #ff00008b.
///
- public static Color DarkBlue => Color.FromUInt32(0xff00008b);
+ public static Color DarkBlue => KnownColor.DarkBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff008b8b.
///
- public static Color DarkCyan => Color.FromUInt32(0xff008b8b);
+ public static Color DarkCyan => KnownColor.DarkCyan.ToColor();
///
/// Gets a color with an ARGB value of #ffb8860b.
///
- public static Color DarkGoldenrod => Color.FromUInt32(0xffb8860b);
+ public static Color DarkGoldenrod => KnownColor.DarkGoldenrod.ToColor();
///
/// Gets a color with an ARGB value of #ffa9a9a9.
///
- public static Color DarkGray => Color.FromUInt32(0xffa9a9a9);
+ public static Color DarkGray => KnownColor.DarkGray.ToColor();
///
/// Gets a color with an ARGB value of #ff006400.
///
- public static Color DarkGreen => Color.FromUInt32(0xff006400);
+ public static Color DarkGreen => KnownColor.DarkGreen.ToColor();
///
/// Gets a color with an ARGB value of #ffbdb76b.
///
- public static Color DarkKhaki => Color.FromUInt32(0xffbdb76b);
+ public static Color DarkKhaki => KnownColor.DarkKhaki.ToColor();
///
/// Gets a color with an ARGB value of #ff8b008b.
///
- public static Color DarkMagenta => Color.FromUInt32(0xff8b008b);
+ public static Color DarkMagenta => KnownColor.DarkMagenta.ToColor();
///
/// Gets a color with an ARGB value of #ff556b2f.
///
- public static Color DarkOliveGreen => Color.FromUInt32(0xff556b2f);
+ public static Color DarkOliveGreen => KnownColor.DarkOliveGreen.ToColor();
///
/// Gets a color with an ARGB value of #ffff8c00.
///
- public static Color DarkOrange => Color.FromUInt32(0xffff8c00);
+ public static Color DarkOrange => KnownColor.DarkOrange.ToColor();
///
/// Gets a color with an ARGB value of #ff9932cc.
///
- public static Color DarkOrchid => Color.FromUInt32(0xff9932cc);
+ public static Color DarkOrchid => KnownColor.DarkOrchid.ToColor();
///
/// Gets a color with an ARGB value of #ff8b0000.
///
- public static Color DarkRed => Color.FromUInt32(0xff8b0000);
+ public static Color DarkRed => KnownColor.DarkRed.ToColor();
///
/// Gets a color with an ARGB value of #ffe9967a.
///
- public static Color DarkSalmon => Color.FromUInt32(0xffe9967a);
+ public static Color DarkSalmon => KnownColor.DarkSalmon.ToColor();
///
/// Gets a color with an ARGB value of #ff8fbc8f.
///
- public static Color DarkSeaGreen => Color.FromUInt32(0xff8fbc8f);
+ public static Color DarkSeaGreen => KnownColor.DarkSeaGreen.ToColor();
///
/// Gets a color with an ARGB value of #ff483d8b.
///
- public static Color DarkSlateBlue => Color.FromUInt32(0xff483d8b);
+ public static Color DarkSlateBlue => KnownColor.DarkSlateBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff2f4f4f.
///
- public static Color DarkSlateGray => Color.FromUInt32(0xff2f4f4f);
+ public static Color DarkSlateGray => KnownColor.DarkSlateGray.ToColor();
///
/// Gets a color with an ARGB value of #ff00ced1.
///
- public static Color DarkTurquoise => Color.FromUInt32(0xff00ced1);
+ public static Color DarkTurquoise => KnownColor.DarkTurquoise.ToColor();
///
/// Gets a color with an ARGB value of #ff9400d3.
///
- public static Color DarkViolet => Color.FromUInt32(0xff9400d3);
+ public static Color DarkViolet => KnownColor.DarkViolet.ToColor();
///
/// Gets a color with an ARGB value of #ffff1493.
///
- public static Color DeepPink => Color.FromUInt32(0xffff1493);
+ public static Color DeepPink => KnownColor.DeepPink.ToColor();
///
/// Gets a color with an ARGB value of #ff00bfff.
///
- public static Color DeepSkyBlue => Color.FromUInt32(0xff00bfff);
+ public static Color DeepSkyBlue => KnownColor.DeepSkyBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff696969.
///
- public static Color DimGray => Color.FromUInt32(0xff696969);
+ public static Color DimGray => KnownColor.DimGray.ToColor();
///
/// Gets a color with an ARGB value of #ff1e90ff.
///
- public static Color DodgerBlue => Color.FromUInt32(0xff1e90ff);
+ public static Color DodgerBlue => KnownColor.DodgerBlue.ToColor();
///
/// Gets a color with an ARGB value of #ffb22222.
///
- public static Color Firebrick => Color.FromUInt32(0xffb22222);
+ public static Color Firebrick => KnownColor.Firebrick.ToColor();
///
/// Gets a color with an ARGB value of #fffffaf0.
///
- public static Color FloralWhite => Color.FromUInt32(0xfffffaf0);
+ public static Color FloralWhite => KnownColor.FloralWhite.ToColor();
///
/// Gets a color with an ARGB value of #ff228b22.
///
- public static Color ForestGreen => Color.FromUInt32(0xff228b22);
+ public static Color ForestGreen => KnownColor.ForestGreen.ToColor();
///
/// Gets a color with an ARGB value of #ffff00ff.
///
- public static Color Fuchsia => Color.FromUInt32(0xffff00ff);
+ public static Color Fuchsia => KnownColor.Fuchsia.ToColor();
///
/// Gets a color with an ARGB value of #ffdcdcdc.
///
- public static Color Gainsboro => Color.FromUInt32(0xffdcdcdc);
+ public static Color Gainsboro => KnownColor.Gainsboro.ToColor();
///
/// Gets a color with an ARGB value of #fff8f8ff.
///
- public static Color GhostWhite => Color.FromUInt32(0xfff8f8ff);
+ public static Color GhostWhite => KnownColor.GhostWhite.ToColor();
///
/// Gets a color with an ARGB value of #ffffd700.
///
- public static Color Gold => Color.FromUInt32(0xffffd700);
+ public static Color Gold => KnownColor.Gold.ToColor();
///
/// Gets a color with an ARGB value of #ffdaa520.
///
- public static Color Goldenrod => Color.FromUInt32(0xffdaa520);
+ public static Color Goldenrod => KnownColor.Goldenrod.ToColor();
///
/// Gets a color with an ARGB value of #ff808080.
///
- public static Color Gray => Color.FromUInt32(0xff808080);
+ public static Color Gray => KnownColor.Gray.ToColor();
///
/// Gets a color with an ARGB value of #ff008000.
///
- public static Color Green => Color.FromUInt32(0xff008000);
+ public static Color Green => KnownColor.Green.ToColor();
///
/// Gets a color with an ARGB value of #ffadff2f.
///
- public static Color GreenYellow => Color.FromUInt32(0xffadff2f);
+ public static Color GreenYellow => KnownColor.GreenYellow.ToColor();
///
/// Gets a color with an ARGB value of #fff0fff0.
///
- public static Color Honeydew => Color.FromUInt32(0xfff0fff0);
+ public static Color Honeydew => KnownColor.Honeydew.ToColor();
///
/// Gets a color with an ARGB value of #ffff69b4.
///
- public static Color HotPink => Color.FromUInt32(0xffff69b4);
+ public static Color HotPink => KnownColor.HotPink.ToColor();
///
/// Gets a color with an ARGB value of #ffcd5c5c.
///
- public static Color IndianRed => Color.FromUInt32(0xffcd5c5c);
+ public static Color IndianRed => KnownColor.IndianRed.ToColor();
///
/// Gets a color with an ARGB value of #ff4b0082.
///
- public static Color Indigo => Color.FromUInt32(0xff4b0082);
+ public static Color Indigo => KnownColor.Indigo.ToColor();
///
/// Gets a color with an ARGB value of #fffffff0.
///
- public static Color Ivory => Color.FromUInt32(0xfffffff0);
+ public static Color Ivory => KnownColor.Ivory.ToColor();
///
/// Gets a color with an ARGB value of #fff0e68c.
///
- public static Color Khaki => Color.FromUInt32(0xfff0e68c);
+ public static Color Khaki => KnownColor.Khaki.ToColor();
///
/// Gets a color with an ARGB value of #ffe6e6fa.
///
- public static Color Lavender => Color.FromUInt32(0xffe6e6fa);
+ public static Color Lavender => KnownColor.Lavender.ToColor();
///
/// Gets a color with an ARGB value of #fffff0f5.
///
- public static Color LavenderBlush => Color.FromUInt32(0xfffff0f5);
+ public static Color LavenderBlush => KnownColor.LavenderBlush.ToColor();
///
/// Gets a color with an ARGB value of #ff7cfc00.
///
- public static Color LawnGreen => Color.FromUInt32(0xff7cfc00);
+ public static Color LawnGreen => KnownColor.LawnGreen.ToColor();
///
/// Gets a color with an ARGB value of #fffffacd.
///
- public static Color LemonChiffon => Color.FromUInt32(0xfffffacd);
+ public static Color LemonChiffon => KnownColor.LemonChiffon.ToColor();
///
/// Gets a color with an ARGB value of #ffadd8e6.
///
- public static Color LightBlue => Color.FromUInt32(0xffadd8e6);
+ public static Color LightBlue => KnownColor.LightBlue.ToColor();
///
/// Gets a color with an ARGB value of #fff08080.
///
- public static Color LightCoral => Color.FromUInt32(0xfff08080);
+ public static Color LightCoral => KnownColor.LightCoral.ToColor();
///
/// Gets a color with an ARGB value of #ffe0ffff.
///
- public static Color LightCyan => Color.FromUInt32(0xffe0ffff);
+ public static Color LightCyan => KnownColor.LightCyan.ToColor();
///
/// Gets a color with an ARGB value of #fffafad2.
///
- public static Color LightGoldenrodYellow => Color.FromUInt32(0xfffafad2);
+ public static Color LightGoldenrodYellow => KnownColor.LightGoldenrodYellow.ToColor();
///
/// Gets a color with an ARGB value of #ffd3d3d3.
///
- public static Color LightGray => Color.FromUInt32(0xffd3d3d3);
+ public static Color LightGray => KnownColor.LightGray.ToColor();
///
/// Gets a color with an ARGB value of #ff90ee90.
///
- public static Color LightGreen => Color.FromUInt32(0xff90ee90);
+ public static Color LightGreen => KnownColor.LightGreen.ToColor();
///
/// Gets a color with an ARGB value of #ffffb6c1.
///
- public static Color LightPink => Color.FromUInt32(0xffffb6c1);
+ public static Color LightPink => KnownColor.LightPink.ToColor();
///
/// Gets a color with an ARGB value of #ffffa07a.
///
- public static Color LightSalmon => Color.FromUInt32(0xffffa07a);
+ public static Color LightSalmon => KnownColor.LightSalmon.ToColor();
///
/// Gets a color with an ARGB value of #ff20b2aa.
///
- public static Color LightSeaGreen => Color.FromUInt32(0xff20b2aa);
+ public static Color LightSeaGreen => KnownColor.LightSeaGreen.ToColor();
///
/// Gets a color with an ARGB value of #ff87cefa.
///
- public static Color LightSkyBlue => Color.FromUInt32(0xff87cefa);
+ public static Color LightSkyBlue => KnownColor.LightSkyBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff778899.
///
- public static Color LightSlateGray => Color.FromUInt32(0xff778899);
+ public static Color LightSlateGray => KnownColor.LightSlateGray.ToColor();
///
/// Gets a color with an ARGB value of #ffb0c4de.
///
- public static Color LightSteelBlue => Color.FromUInt32(0xffb0c4de);
+ public static Color LightSteelBlue => KnownColor.LightSteelBlue.ToColor();
///
/// Gets a color with an ARGB value of #ffffffe0.
///
- public static Color LightYellow => Color.FromUInt32(0xffffffe0);
+ public static Color LightYellow => KnownColor.LightYellow.ToColor();
///
/// Gets a color with an ARGB value of #ff00ff00.
///
- public static Color Lime => Color.FromUInt32(0xff00ff00);
+ public static Color Lime => KnownColor.Lime.ToColor();
///
/// Gets a color with an ARGB value of #ff32cd32.
///
- public static Color LimeGreen => Color.FromUInt32(0xff32cd32);
+ public static Color LimeGreen => KnownColor.LimeGreen.ToColor();
///
/// Gets a color with an ARGB value of #fffaf0e6.
///
- public static Color Linen => Color.FromUInt32(0xfffaf0e6);
+ public static Color Linen => KnownColor.Linen.ToColor();
///
/// Gets a color with an ARGB value of #ffff00ff.
///
- public static Color Magenta => Color.FromUInt32(0xffff00ff);
+ public static Color Magenta => KnownColor.Magenta.ToColor();
///
/// Gets a color with an ARGB value of #ff800000.
///
- public static Color Maroon => Color.FromUInt32(0xff800000);
+ public static Color Maroon => KnownColor.Maroon.ToColor();
///
/// Gets a color with an ARGB value of #ff66cdaa.
///
- public static Color MediumAquamarine => Color.FromUInt32(0xff66cdaa);
+ public static Color MediumAquamarine => KnownColor.MediumAquamarine.ToColor();
///
/// Gets a color with an ARGB value of #ff0000cd.
///
- public static Color MediumBlue => Color.FromUInt32(0xff0000cd);
+ public static Color MediumBlue => KnownColor.MediumBlue.ToColor();
///
/// Gets a color with an ARGB value of #ffba55d3.
///
- public static Color MediumOrchid => Color.FromUInt32(0xffba55d3);
+ public static Color MediumOrchid => KnownColor.MediumOrchid.ToColor();
///
/// Gets a color with an ARGB value of #ff9370db.
///
- public static Color MediumPurple => Color.FromUInt32(0xff9370db);
+ public static Color MediumPurple => KnownColor.MediumPurple.ToColor();
///
/// Gets a color with an ARGB value of #ff3cb371.
///
- public static Color MediumSeaGreen => Color.FromUInt32(0xff3cb371);
+ public static Color MediumSeaGreen => KnownColor.MediumSeaGreen.ToColor();
///
/// Gets a color with an ARGB value of #ff7b68ee.
///
- public static Color MediumSlateBlue => Color.FromUInt32(0xff7b68ee);
+ public static Color MediumSlateBlue => KnownColor.MediumSlateBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff00fa9a.
///
- public static Color MediumSpringGreen => Color.FromUInt32(0xff00fa9a);
+ public static Color MediumSpringGreen => KnownColor.MediumSpringGreen.ToColor();
///
/// Gets a color with an ARGB value of #ff48d1cc.
///
- public static Color MediumTurquoise => Color.FromUInt32(0xff48d1cc);
+ public static Color MediumTurquoise => KnownColor.MediumTurquoise.ToColor();
///
/// Gets a color with an ARGB value of #ffc71585.
///
- public static Color MediumVioletRed => Color.FromUInt32(0xffc71585);
+ public static Color MediumVioletRed => KnownColor.MediumVioletRed.ToColor();
///
/// Gets a color with an ARGB value of #ff191970.
///
- public static Color MidnightBlue => Color.FromUInt32(0xff191970);
+ public static Color MidnightBlue => KnownColor.MidnightBlue.ToColor();
///
/// Gets a color with an ARGB value of #fff5fffa.
///
- public static Color MintCream => Color.FromUInt32(0xfff5fffa);
+ public static Color MintCream => KnownColor.MintCream.ToColor();
///
/// Gets a color with an ARGB value of #ffffe4e1.
///
- public static Color MistyRose => Color.FromUInt32(0xffffe4e1);
+ public static Color MistyRose => KnownColor.MistyRose.ToColor();
///
/// Gets a color with an ARGB value of #ffffe4b5.
///
- public static Color Moccasin => Color.FromUInt32(0xffffe4b5);
+ public static Color Moccasin => KnownColor.Moccasin.ToColor();
///
/// Gets a color with an ARGB value of #ffffdead.
///
- public static Color NavajoWhite => Color.FromUInt32(0xffffdead);
+ public static Color NavajoWhite => KnownColor.NavajoWhite.ToColor();
///
/// Gets a color with an ARGB value of #ff000080.
///
- public static Color Navy => Color.FromUInt32(0xff000080);
+ public static Color Navy => KnownColor.Navy.ToColor();
///
/// Gets a color with an ARGB value of #fffdf5e6.
///
- public static Color OldLace => Color.FromUInt32(0xfffdf5e6);
+ public static Color OldLace => KnownColor.OldLace.ToColor();
///
/// Gets a color with an ARGB value of #ff808000.
///
- public static Color Olive => Color.FromUInt32(0xff808000);
+ public static Color Olive => KnownColor.Olive.ToColor();
///
/// Gets a color with an ARGB value of #ff6b8e23.
///
- public static Color OliveDrab => Color.FromUInt32(0xff6b8e23);
+ public static Color OliveDrab => KnownColor.OliveDrab.ToColor();
///
/// Gets a color with an ARGB value of #ffffa500.
///
- public static Color Orange => Color.FromUInt32(0xffffa500);
+ public static Color Orange => KnownColor.Orange.ToColor();
///
/// Gets a color with an ARGB value of #ffff4500.
///
- public static Color OrangeRed => Color.FromUInt32(0xffff4500);
+ public static Color OrangeRed => KnownColor.OrangeRed.ToColor();
///
/// Gets a color with an ARGB value of #ffda70d6.
///
- public static Color Orchid => Color.FromUInt32(0xffda70d6);
+ public static Color Orchid => KnownColor.Orchid.ToColor();
///
/// Gets a color with an ARGB value of #ffeee8aa.
///
- public static Color PaleGoldenrod => Color.FromUInt32(0xffeee8aa);
+ public static Color PaleGoldenrod => KnownColor.PaleGoldenrod.ToColor();
///
/// Gets a color with an ARGB value of #ff98fb98.
///
- public static Color PaleGreen => Color.FromUInt32(0xff98fb98);
+ public static Color PaleGreen => KnownColor.PaleGreen.ToColor();
///
/// Gets a color with an ARGB value of #ffafeeee.
///
- public static Color PaleTurquoise => Color.FromUInt32(0xffafeeee);
+ public static Color PaleTurquoise => KnownColor.PaleTurquoise.ToColor();
///
/// Gets a color with an ARGB value of #ffdb7093.
///
- public static Color PaleVioletRed => Color.FromUInt32(0xffdb7093);
+ public static Color PaleVioletRed => KnownColor.PaleVioletRed.ToColor();
///
/// Gets a color with an ARGB value of #ffffefd5.
///
- public static Color PapayaWhip => Color.FromUInt32(0xffffefd5);
+ public static Color PapayaWhip => KnownColor.PapayaWhip.ToColor();
///
/// Gets a color with an ARGB value of #ffffdab9.
///
- public static Color PeachPuff => Color.FromUInt32(0xffffdab9);
+ public static Color PeachPuff => KnownColor.PeachPuff.ToColor();
///
/// Gets a color with an ARGB value of #ffcd853f.
///
- public static Color Peru => Color.FromUInt32(0xffcd853f);
+ public static Color Peru => KnownColor.Peru.ToColor();
///
/// Gets a color with an ARGB value of #ffffc0cb.
///
- public static Color Pink => Color.FromUInt32(0xffffc0cb);
+ public static Color Pink => KnownColor.Pink.ToColor();
///
/// Gets a color with an ARGB value of #ffdda0dd.
///
- public static Color Plum => Color.FromUInt32(0xffdda0dd);
+ public static Color Plum => KnownColor.Plum.ToColor();
///
/// Gets a color with an ARGB value of #ffb0e0e6.
///
- public static Color PowderBlue => Color.FromUInt32(0xffb0e0e6);
+ public static Color PowderBlue => KnownColor.PowderBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff800080.
///
- public static Color Purple => Color.FromUInt32(0xff800080);
+ public static Color Purple => KnownColor.Purple.ToColor();
///
/// Gets a color with an ARGB value of #ffff0000.
///
- public static Color Red => Color.FromUInt32(0xffff0000);
+ public static Color Red => KnownColor.Red.ToColor();
///
/// Gets a color with an ARGB value of #ffbc8f8f.
///
- public static Color RosyBrown => Color.FromUInt32(0xffbc8f8f);
+ public static Color RosyBrown => KnownColor.RosyBrown.ToColor();
///
/// Gets a color with an ARGB value of #ff4169e1.
///
- public static Color RoyalBlue => Color.FromUInt32(0xff4169e1);
+ public static Color RoyalBlue => KnownColor.RoyalBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff8b4513.
///
- public static Color SaddleBrown => Color.FromUInt32(0xff8b4513);
+ public static Color SaddleBrown => KnownColor.SaddleBrown.ToColor();
///
/// Gets a color with an ARGB value of #fffa8072.
///
- public static Color Salmon => Color.FromUInt32(0xfffa8072);
+ public static Color Salmon => KnownColor.Salmon.ToColor();
///
/// Gets a color with an ARGB value of #fff4a460.
///
- public static Color SandyBrown => Color.FromUInt32(0xfff4a460);
+ public static Color SandyBrown => KnownColor.SandyBrown.ToColor();
///
/// Gets a color with an ARGB value of #ff2e8b57.
///
- public static Color SeaGreen => Color.FromUInt32(0xff2e8b57);
+ public static Color SeaGreen => KnownColor.SeaGreen.ToColor();
///
/// Gets a color with an ARGB value of #fffff5ee.
///
- public static Color SeaShell => Color.FromUInt32(0xfffff5ee);
+ public static Color SeaShell => KnownColor.SeaShell.ToColor();
///
/// Gets a color with an ARGB value of #ffa0522d.
///
- public static Color Sienna => Color.FromUInt32(0xffa0522d);
+ public static Color Sienna => KnownColor.Sienna.ToColor();
///
/// Gets a color with an ARGB value of #ffc0c0c0.
///
- public static Color Silver => Color.FromUInt32(0xffc0c0c0);
+ public static Color Silver => KnownColor.Silver.ToColor();
///
/// Gets a color with an ARGB value of #ff87ceeb.
///
- public static Color SkyBlue => Color.FromUInt32(0xff87ceeb);
+ public static Color SkyBlue => KnownColor.SkyBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff6a5acd.
///
- public static Color SlateBlue => Color.FromUInt32(0xff6a5acd);
+ public static Color SlateBlue => KnownColor.SlateBlue.ToColor();
///
/// Gets a color with an ARGB value of #ff708090.
///
- public static Color SlateGray => Color.FromUInt32(0xff708090);
+ public static Color SlateGray => KnownColor.SlateGray.ToColor();
///
/// Gets a color with an ARGB value of #fffffafa.
///
- public static Color Snow => Color.FromUInt32(0xfffffafa);
+ public static Color Snow => KnownColor.Snow.ToColor();
///
/// Gets a color with an ARGB value of #ff00ff7f.
///
- public static Color SpringGreen => Color.FromUInt32(0xff00ff7f);
+ public static Color SpringGreen => KnownColor.SpringGreen.ToColor();
///
/// Gets a color with an ARGB value of #ff4682b4.
///
- public static Color SteelBlue => Color.FromUInt32(0xff4682b4);
+ public static Color SteelBlue => KnownColor.SteelBlue.ToColor();
///
/// Gets a color with an ARGB value of #ffd2b48c.
///
- public static Color Tan => Color.FromUInt32(0xffd2b48c);
+ public static Color Tan => KnownColor.Tan.ToColor();
///
/// Gets a color with an ARGB value of #ff008080.
///
- public static Color Teal => Color.FromUInt32(0xff008080);
+ public static Color Teal => KnownColor.Teal.ToColor();
///
/// Gets a color with an ARGB value of #ffd8bfd8.
///
- public static Color Thistle => Color.FromUInt32(0xffd8bfd8);
+ public static Color Thistle => KnownColor.Thistle.ToColor();
///
/// Gets a color with an ARGB value of #ffff6347.
///
- public static Color Tomato => Color.FromUInt32(0xffff6347);
+ public static Color Tomato => KnownColor.Tomato.ToColor();
///
/// Gets a color with an ARGB value of #00ffffff.
///
- public static Color Transparent => Color.FromUInt32(0x00ffffff);
+ public static Color Transparent => KnownColor.Transparent.ToColor();
///
/// Gets a color with an ARGB value of #ff40e0d0.
///
- public static Color Turquoise => Color.FromUInt32(0xff40e0d0);
+ public static Color Turquoise => KnownColor.Turquoise.ToColor();
///
/// Gets a color with an ARGB value of #ffee82ee.
///
- public static Color Violet => Color.FromUInt32(0xffee82ee);
+ public static Color Violet => KnownColor.Violet.ToColor();
///
/// Gets a color with an ARGB value of #fff5deb3.
///
- public static Color Wheat => Color.FromUInt32(0xfff5deb3);
+ public static Color Wheat => KnownColor.Wheat.ToColor();
///
/// Gets a color with an ARGB value of #ffffffff.
///
- public static Color White => Color.FromUInt32(0xffffffff);
+ public static Color White => KnownColor.White.ToColor();
///
/// Gets a color with an ARGB value of #fff5f5f5.
///
- public static Color WhiteSmoke => Color.FromUInt32(0xfff5f5f5);
+ public static Color WhiteSmoke => KnownColor.WhiteSmoke.ToColor();
///
/// Gets a color with an ARGB value of #ffffff00.
///
- public static Color Yellow => Color.FromUInt32(0xffffff00);
+ public static Color Yellow => KnownColor.Yellow.ToColor();
///
/// Gets a color with an ARGB value of #ff9acd32.
///
- public static Color YellowGreen => Color.FromUInt32(0xff9acd32);
+ public static Color YellowGreen => KnownColor.YellowGreen.ToColor();
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Media/KnownColors.cs b/src/Avalonia.Visuals/Media/KnownColors.cs
new file mode 100644
index 0000000000..0887d2c913
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/KnownColors.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace Avalonia.Media
+{
+ internal static class KnownColors
+ {
+ private static readonly IReadOnlyDictionary _knownColorNames;
+ private static readonly IReadOnlyDictionary _knownColors;
+ private static readonly Dictionary _knownBrushes;
+
+ static KnownColors()
+ {
+ var knownColorNames = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ var knownColors = new Dictionary();
+
+ foreach (var field in typeof(KnownColor).GetRuntimeFields())
+ {
+ if (field.FieldType != typeof(KnownColor)) continue;
+ var knownColor = (KnownColor)field.GetValue(null);
+ if (knownColor == KnownColor.None) continue;
+
+ knownColorNames.Add(field.Name, knownColor);
+
+ // some known colors have the same value, so use the first
+ if (!knownColors.ContainsKey((uint)knownColor))
+ {
+ knownColors.Add((uint)knownColor, field.Name);
+ }
+ }
+
+ _knownColorNames = knownColorNames;
+ _knownColors = knownColors;
+ _knownBrushes = new Dictionary();
+ }
+
+ public static ISolidColorBrush GetKnownBrush(string s)
+ {
+ var color = GetKnownColor(s);
+ return color != KnownColor.None ? color.ToBrush() : null;
+ }
+
+ public static KnownColor GetKnownColor(string s)
+ {
+ if (_knownColorNames.TryGetValue(s, out var color))
+ {
+ return color;
+ }
+
+ return KnownColor.None;
+ }
+
+ public static string GetKnownColorName(uint rgb)
+ {
+ return _knownColors.TryGetValue(rgb, out var name) ? name : null;
+ }
+
+ public static Color ToColor(this KnownColor color)
+ {
+ return Color.FromUInt32((uint)color);
+ }
+
+ public static ISolidColorBrush ToBrush(this KnownColor color)
+ {
+ lock (_knownBrushes)
+ {
+ if (!_knownBrushes.TryGetValue(color, out var brush))
+ {
+ brush = new Immutable.ImmutableSolidColorBrush(color.ToColor());
+ _knownBrushes.Add(color, brush);
+ }
+
+ return brush;
+ }
+ }
+ }
+
+ internal enum KnownColor : uint
+ {
+ None,
+ AliceBlue = 0xfff0f8ff,
+ AntiqueWhite = 0xfffaebd7,
+ Aqua = 0xff00ffff,
+ Aquamarine = 0xff7fffd4,
+ Azure = 0xfff0ffff,
+ Beige = 0xfff5f5dc,
+ Bisque = 0xffffe4c4,
+ Black = 0xff000000,
+ BlanchedAlmond = 0xffffebcd,
+ Blue = 0xff0000ff,
+ BlueViolet = 0xff8a2be2,
+ Brown = 0xffa52a2a,
+ BurlyWood = 0xffdeb887,
+ CadetBlue = 0xff5f9ea0,
+ Chartreuse = 0xff7fff00,
+ Chocolate = 0xffd2691e,
+ Coral = 0xffff7f50,
+ CornflowerBlue = 0xff6495ed,
+ Cornsilk = 0xfffff8dc,
+ Crimson = 0xffdc143c,
+ Cyan = 0xff00ffff,
+ DarkBlue = 0xff00008b,
+ DarkCyan = 0xff008b8b,
+ DarkGoldenrod = 0xffb8860b,
+ DarkGray = 0xffa9a9a9,
+ DarkGreen = 0xff006400,
+ DarkKhaki = 0xffbdb76b,
+ DarkMagenta = 0xff8b008b,
+ DarkOliveGreen = 0xff556b2f,
+ DarkOrange = 0xffff8c00,
+ DarkOrchid = 0xff9932cc,
+ DarkRed = 0xff8b0000,
+ DarkSalmon = 0xffe9967a,
+ DarkSeaGreen = 0xff8fbc8f,
+ DarkSlateBlue = 0xff483d8b,
+ DarkSlateGray = 0xff2f4f4f,
+ DarkTurquoise = 0xff00ced1,
+ DarkViolet = 0xff9400d3,
+ DeepPink = 0xffff1493,
+ DeepSkyBlue = 0xff00bfff,
+ DimGray = 0xff696969,
+ DodgerBlue = 0xff1e90ff,
+ Firebrick = 0xffb22222,
+ FloralWhite = 0xfffffaf0,
+ ForestGreen = 0xff228b22,
+ Fuchsia = 0xffff00ff,
+ Gainsboro = 0xffdcdcdc,
+ GhostWhite = 0xfff8f8ff,
+ Gold = 0xffffd700,
+ Goldenrod = 0xffdaa520,
+ Gray = 0xff808080,
+ Green = 0xff008000,
+ GreenYellow = 0xffadff2f,
+ Honeydew = 0xfff0fff0,
+ HotPink = 0xffff69b4,
+ IndianRed = 0xffcd5c5c,
+ Indigo = 0xff4b0082,
+ Ivory = 0xfffffff0,
+ Khaki = 0xfff0e68c,
+ Lavender = 0xffe6e6fa,
+ LavenderBlush = 0xfffff0f5,
+ LawnGreen = 0xff7cfc00,
+ LemonChiffon = 0xfffffacd,
+ LightBlue = 0xffadd8e6,
+ LightCoral = 0xfff08080,
+ LightCyan = 0xffe0ffff,
+ LightGoldenrodYellow = 0xfffafad2,
+ LightGreen = 0xff90ee90,
+ LightGray = 0xffd3d3d3,
+ LightPink = 0xffffb6c1,
+ LightSalmon = 0xffffa07a,
+ LightSeaGreen = 0xff20b2aa,
+ LightSkyBlue = 0xff87cefa,
+ LightSlateGray = 0xff778899,
+ LightSteelBlue = 0xffb0c4de,
+ LightYellow = 0xffffffe0,
+ Lime = 0xff00ff00,
+ LimeGreen = 0xff32cd32,
+ Linen = 0xfffaf0e6,
+ Magenta = 0xffff00ff,
+ Maroon = 0xff800000,
+ MediumAquamarine = 0xff66cdaa,
+ MediumBlue = 0xff0000cd,
+ MediumOrchid = 0xffba55d3,
+ MediumPurple = 0xff9370db,
+ MediumSeaGreen = 0xff3cb371,
+ MediumSlateBlue = 0xff7b68ee,
+ MediumSpringGreen = 0xff00fa9a,
+ MediumTurquoise = 0xff48d1cc,
+ MediumVioletRed = 0xffc71585,
+ MidnightBlue = 0xff191970,
+ MintCream = 0xfff5fffa,
+ MistyRose = 0xffffe4e1,
+ Moccasin = 0xffffe4b5,
+ NavajoWhite = 0xffffdead,
+ Navy = 0xff000080,
+ OldLace = 0xfffdf5e6,
+ Olive = 0xff808000,
+ OliveDrab = 0xff6b8e23,
+ Orange = 0xffffa500,
+ OrangeRed = 0xffff4500,
+ Orchid = 0xffda70d6,
+ PaleGoldenrod = 0xffeee8aa,
+ PaleGreen = 0xff98fb98,
+ PaleTurquoise = 0xffafeeee,
+ PaleVioletRed = 0xffdb7093,
+ PapayaWhip = 0xffffefd5,
+ PeachPuff = 0xffffdab9,
+ Peru = 0xffcd853f,
+ Pink = 0xffffc0cb,
+ Plum = 0xffdda0dd,
+ PowderBlue = 0xffb0e0e6,
+ Purple = 0xff800080,
+ Red = 0xffff0000,
+ RosyBrown = 0xffbc8f8f,
+ RoyalBlue = 0xff4169e1,
+ SaddleBrown = 0xff8b4513,
+ Salmon = 0xfffa8072,
+ SandyBrown = 0xfff4a460,
+ SeaGreen = 0xff2e8b57,
+ SeaShell = 0xfffff5ee,
+ Sienna = 0xffa0522d,
+ Silver = 0xffc0c0c0,
+ SkyBlue = 0xff87ceeb,
+ SlateBlue = 0xff6a5acd,
+ SlateGray = 0xff708090,
+ Snow = 0xfffffafa,
+ SpringGreen = 0xff00ff7f,
+ SteelBlue = 0xff4682b4,
+ Tan = 0xffd2b48c,
+ Teal = 0xff008080,
+ Thistle = 0xffd8bfd8,
+ Tomato = 0xffff6347,
+ Transparent = 0x00ffffff,
+ Turquoise = 0xff40e0d0,
+ Violet = 0xffee82ee,
+ Wheat = 0xfff5deb3,
+ White = 0xffffffff,
+ WhiteSmoke = 0xfff5f5f5,
+ Yellow = 0xffffff00,
+ YellowGreen = 0xff9acd32
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs
index 5fbd082967..d0c3edfeb2 100644
--- a/src/Avalonia.Visuals/Point.cs
+++ b/src/Avalonia.Visuals/Point.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -173,17 +174,12 @@ namespace Avalonia
/// The .
public static Point Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToList();
-
- if (parts.Count == 2)
- {
- return new Point(double.Parse(parts[0], culture), double.Parse(parts[1], culture));
- }
- else
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Point"))
{
- throw new FormatException("Invalid Point.");
+ return new Point(
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble()
+ );
}
}
diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs
index d562429fc7..748928ada3 100644
--- a/src/Avalonia.Visuals/Rect.cs
+++ b/src/Avalonia.Visuals/Rect.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -490,21 +491,14 @@ namespace Avalonia
/// The parsed .
public static Rect Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToList();
-
- if (parts.Count == 4)
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Rect"))
{
return new Rect(
- double.Parse(parts[0], culture),
- double.Parse(parts[1], culture),
- double.Parse(parts[2], culture),
- double.Parse(parts[3], culture));
- }
- else
- {
- throw new FormatException("Invalid Rect.");
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble()
+ );
}
}
}
diff --git a/src/Avalonia.Visuals/RelativePoint.cs b/src/Avalonia.Visuals/RelativePoint.cs
index cc34feb5f3..a2ef0e6725 100644
--- a/src/Avalonia.Visuals/RelativePoint.cs
+++ b/src/Avalonia.Visuals/RelativePoint.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -157,37 +158,32 @@ namespace Avalonia
/// The parsed .
public static RelativePoint Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToList();
-
- if (parts.Count == 2)
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid RelativePoint"))
{
+ var x = tokenizer.ReadString();
+ var y = tokenizer.ReadString();
+
var unit = RelativeUnit.Absolute;
var scale = 1.0;
- if (parts[0].EndsWith("%"))
+ if (x.EndsWith("%"))
{
- if (!parts[1].EndsWith("%"))
+ if (!y.EndsWith("%"))
{
throw new FormatException("If one coordinate is relative, both must be.");
}
- parts[0] = parts[0].TrimEnd('%');
- parts[1] = parts[1].TrimEnd('%');
+ x = x.TrimEnd('%');
+ y = y.TrimEnd('%');
unit = RelativeUnit.Relative;
scale = 0.01;
}
return new RelativePoint(
- double.Parse(parts[0], culture) * scale,
- double.Parse(parts[1], culture) * scale,
+ double.Parse(x, culture) * scale,
+ double.Parse(y, culture) * scale,
unit);
}
- else
- {
- throw new FormatException("Invalid Point.");
- }
}
}
}
diff --git a/src/Avalonia.Visuals/RelativeRect.cs b/src/Avalonia.Visuals/RelativeRect.cs
index a11f080e94..c13c3282db 100644
--- a/src/Avalonia.Visuals/RelativeRect.cs
+++ b/src/Avalonia.Visuals/RelativeRect.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -12,6 +13,8 @@ namespace Avalonia
///
public struct RelativeRect : IEquatable
{
+ private static readonly char[] PercentChar = { '%' };
+
///
/// A rectangle that represents 100% of an area.
///
@@ -159,7 +162,7 @@ namespace Avalonia
Rect.Width * size.Width,
Rect.Height * size.Height);
}
-
+
///
/// Parses a string.
///
@@ -168,43 +171,43 @@ namespace Avalonia
/// The parsed .
public static RelativeRect Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToList();
-
- if (parts.Count == 4)
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid RelativeRect"))
{
+ var x = tokenizer.ReadString();
+ var y = tokenizer.ReadString();
+ var width = tokenizer.ReadString();
+ var height = tokenizer.ReadString();
+
var unit = RelativeUnit.Absolute;
var scale = 1.0;
- if (parts[0].EndsWith("%"))
+ var xRelative = x.EndsWith("%", StringComparison.Ordinal);
+ var yRelative = y.EndsWith("%", StringComparison.Ordinal);
+ var widthRelative = width.EndsWith("%", StringComparison.Ordinal);
+ var heightRelative = height.EndsWith("%", StringComparison.Ordinal);
+
+ if (xRelative && yRelative && widthRelative && heightRelative)
{
- if (!parts[1].EndsWith("%")
- || !parts[2].EndsWith("%")
- || !parts[3].EndsWith("%"))
- {
- throw new FormatException("If one coordinate is relative, all other must be too.");
- }
-
- parts[0] = parts[0].TrimEnd('%');
- parts[1] = parts[1].TrimEnd('%');
- parts[2] = parts[2].TrimEnd('%');
- parts[3] = parts[3].TrimEnd('%');
+ x = x.TrimEnd(PercentChar);
+ y = y.TrimEnd(PercentChar);
+ width = width.TrimEnd(PercentChar);
+ height = height.TrimEnd(PercentChar);
+
unit = RelativeUnit.Relative;
scale = 0.01;
}
+ else if (xRelative || yRelative || widthRelative || heightRelative)
+ {
+ throw new FormatException("If one coordinate is relative, all must be.");
+ }
return new RelativeRect(
- double.Parse(parts[0], culture) * scale,
- double.Parse(parts[1], culture) * scale,
- double.Parse(parts[2], culture) * scale,
- double.Parse(parts[3], culture) * scale,
+ double.Parse(x, culture) * scale,
+ double.Parse(y, culture) * scale,
+ double.Parse(width, culture) * scale,
+ double.Parse(height, culture) * scale,
unit);
}
- else
- {
- throw new FormatException("Invalid RelativeRect.");
- }
}
}
}
diff --git a/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs b/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs
index 5dff3715b3..9cf849f59b 100644
--- a/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs
+++ b/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs
@@ -41,12 +41,12 @@ namespace Avalonia.Rendering
{
add
{
+ _tick += value;
+
if (_subscriberCount++ == 0)
{
Start();
}
-
- _tick += value;
}
remove
diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs
index 6ad87c6120..c5eaa33b41 100644
--- a/src/Avalonia.Visuals/Size.cs
+++ b/src/Avalonia.Visuals/Size.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -153,17 +154,11 @@ namespace Avalonia
/// The .
public static Size Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToList();
-
- if (parts.Count == 2)
- {
- return new Size(double.Parse(parts[0], culture), double.Parse(parts[1], culture));
- }
- else
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Size"))
{
- throw new FormatException("Invalid Size.");
+ return new Size(
+ tokenizer.ReadDouble(),
+ tokenizer.ReadDouble());
}
}
diff --git a/src/Avalonia.Visuals/Thickness.cs b/src/Avalonia.Visuals/Thickness.cs
index ead9fd004a..a5ca0a04a8 100644
--- a/src/Avalonia.Visuals/Thickness.cs
+++ b/src/Avalonia.Visuals/Thickness.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 Avalonia.Utilities;
using System;
using System.Globalization;
using System.Linq;
@@ -168,28 +169,22 @@ namespace Avalonia
/// The .
public static Thickness Parse(string s, CultureInfo culture)
{
- var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.Trim())
- .ToList();
-
- switch (parts.Count)
+ using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Thickness"))
{
- case 1:
- var uniform = double.Parse(parts[0], culture);
- return new Thickness(uniform);
- case 2:
- var horizontal = double.Parse(parts[0], culture);
- var vertical = double.Parse(parts[1], culture);
- return new Thickness(horizontal, vertical);
- case 4:
- var left = double.Parse(parts[0], culture);
- var top = double.Parse(parts[1], culture);
- var right = double.Parse(parts[2], culture);
- var bottom = double.Parse(parts[3], culture);
- return new Thickness(left, top, right, bottom);
+ var a = tokenizer.ReadDouble();
+
+ if (tokenizer.TryReadDouble(out var b))
+ {
+ if (tokenizer.TryReadDouble(out var c))
+ {
+ return new Thickness(a, b, c, tokenizer.ReadDouble());
+ }
+
+ return new Thickness(a, b);
+ }
+
+ return new Thickness(a);
}
-
- throw new FormatException("Invalid Thickness.");
}
///
diff --git a/src/Gtk/Avalonia.Gtk3/CursorFactory.cs b/src/Gtk/Avalonia.Gtk3/CursorFactory.cs
index ac547b8bc2..d6a3c1f260 100644
--- a/src/Gtk/Avalonia.Gtk3/CursorFactory.cs
+++ b/src/Gtk/Avalonia.Gtk3/CursorFactory.cs
@@ -32,7 +32,10 @@ namespace Avalonia.Gtk3
{StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner},
{StandardCursorType.TopRightCorner, CursorType.TopRightCorner},
{StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner},
- {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner}
+ {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner},
+ {StandardCursorType.DragCopy, CursorType.CenterPtr},
+ {StandardCursorType.DragMove, CursorType.Fleur},
+ {StandardCursorType.DragLink, CursorType.Cross},
};
private static readonly Dictionary Cache =
diff --git a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
index 5f6be91571..c31c131ea9 100644
--- a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
+++ b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0
True
@@ -19,4 +19,4 @@
-
+
\ No newline at end of file
diff --git a/src/OSX/Avalonia.MonoMac/Cursor.cs b/src/OSX/Avalonia.MonoMac/Cursor.cs
index 10445e62e2..d9370e527b 100644
--- a/src/OSX/Avalonia.MonoMac/Cursor.cs
+++ b/src/OSX/Avalonia.MonoMac/Cursor.cs
@@ -51,6 +51,10 @@ namespace Avalonia.MonoMac
[StandardCursorType.TopSide] = NSCursor.ResizeUpCursor,
[StandardCursorType.UpArrow] = NSCursor.ResizeUpCursor,
[StandardCursorType.Wait] = NSCursor.ArrowCursor, //TODO
+ [StandardCursorType.DragMove] = NSCursor.DragCopyCursor, // TODO
+ [StandardCursorType.DragCopy] = NSCursor.DragCopyCursor,
+ [StandardCursorType.DragLink] = NSCursor.DragLinkCursor,
+
};
}
diff --git a/src/OSX/Avalonia.MonoMac/DragSource.cs b/src/OSX/Avalonia.MonoMac/DragSource.cs
new file mode 100644
index 0000000000..41a206b580
--- /dev/null
+++ b/src/OSX/Avalonia.MonoMac/DragSource.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
+using MonoMac;
+using MonoMac.AppKit;
+using MonoMac.CoreGraphics;
+using MonoMac.Foundation;
+using MonoMac.OpenGL;
+
+namespace Avalonia.MonoMac
+{
+ public class DragSource : NSDraggingSource, IPlatformDragSource
+ {
+ private const string NSPasteboardTypeString = "public.utf8-plain-text";
+ private const string NSPasteboardTypeFileUrl = "public.file-url";
+
+ private readonly Subject _result = new Subject();
+ private readonly IInputManager _inputManager;
+ private DragDropEffects _allowedEffects;
+
+ public override bool IgnoreModifierKeysWhileDragging => false;
+
+ public DragSource()
+ {
+ _inputManager = AvaloniaLocator.Current.GetService();
+ }
+
+ private string DataFormatToUTI(string s)
+ {
+ if (s == DataFormats.FileNames)
+ return NSPasteboardTypeFileUrl;
+ if (s == DataFormats.Text)
+ return NSPasteboardTypeString;
+ return s;
+ }
+
+ private NSDraggingItem CreateDraggingItem(string format, object data)
+ {
+ var pasteboardItem = new NSPasteboardItem();
+ NSData nsData;
+ if (data is string s)
+ {
+ if (format == DataFormats.FileNames)
+ s = new Uri(s).AbsoluteUri; // Ensure file uris...
+ nsData = NSData.FromString(s);
+ }
+ else if (data is Stream strm)
+ nsData = NSData.FromStream(strm);
+ else if (data is byte[] bytes)
+ nsData = NSData.FromArray(bytes);
+ else
+ {
+ BinaryFormatter bf = new BinaryFormatter();
+ using (var ms = new MemoryStream())
+ {
+ bf.Serialize(ms, data);
+ ms.Position = 0;
+ nsData = NSData.FromStream(ms);
+ }
+ }
+ pasteboardItem.SetDataForType(nsData, DataFormatToUTI(format));
+
+ NSPasteboardWriting writing = new NSPasteboardWriting(pasteboardItem.Handle);
+
+ return new NSDraggingItem(writing);
+ }
+
+ public IEnumerable CreateDraggingItems(string format, object data)
+ {
+ if (format == DataFormats.FileNames && data is IEnumerable files)
+ {
+ foreach (var file in files)
+ yield return CreateDraggingItem(format, file);
+
+ yield break;
+ }
+
+ yield return CreateDraggingItem(format, data);
+ }
+
+
+ public async Task DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+ {
+ // We need the TopLevelImpl + a mouse location so we just wait for the next event.
+ var mouseEv = await _inputManager.PreProcess.OfType().FirstAsync();
+ var view = ((mouseEv.Root as TopLevel)?.PlatformImpl as TopLevelImpl)?.View;
+ if (view == null)
+ return DragDropEffects.None;
+
+ // Prepare the source event:
+ var pt = view.TranslateLocalPoint(mouseEv.Position).ToMonoMacPoint();
+ var ev = NSEvent.MouseEvent(NSEventType.LeftMouseDown, pt, 0, 0, 0, null, 0, 0, 0);
+
+ _allowedEffects = allowedEffects;
+ var items = data.GetDataFormats().SelectMany(fmt => CreateDraggingItems(fmt, data.Get(fmt))).ToArray();
+ view.BeginDraggingSession(items ,ev, this);
+
+ return await _result;
+ }
+
+ public override NSDragOperation DraggingSourceOperationMaskForLocal(bool flag)
+ {
+ return DraggingInfo.ConvertDragOperation(_allowedEffects);
+ }
+
+ public override void DraggedImageEndedAtOperation(NSImage image, CGPoint screenPoint, NSDragOperation operation)
+ {
+ _result.OnNext(DraggingInfo.ConvertDragOperation(operation));
+ _result.OnCompleted();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/OSX/Avalonia.MonoMac/DraggingInfo.cs b/src/OSX/Avalonia.MonoMac/DraggingInfo.cs
new file mode 100644
index 0000000000..fc5f52713e
--- /dev/null
+++ b/src/OSX/Avalonia.MonoMac/DraggingInfo.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Input;
+using MonoMac.AppKit;
+using MonoMac.Foundation;
+
+namespace Avalonia.MonoMac
+{
+ class DraggingInfo : IDataObject
+ {
+ private readonly NSDraggingInfo _info;
+
+ public DraggingInfo(NSDraggingInfo info)
+ {
+ _info = info;
+ }
+
+ internal static NSDragOperation ConvertDragOperation(DragDropEffects d)
+ {
+ NSDragOperation result = NSDragOperation.None;
+ if (d.HasFlag(DragDropEffects.Copy))
+ result |= NSDragOperation.Copy;
+ if (d.HasFlag(DragDropEffects.Link))
+ result |= NSDragOperation.Link;
+ if (d.HasFlag(DragDropEffects.Move))
+ result |= NSDragOperation.Move;
+ return result;
+ }
+
+ internal static DragDropEffects ConvertDragOperation(NSDragOperation d)
+ {
+ DragDropEffects result = DragDropEffects.None;
+ if (d.HasFlag(NSDragOperation.Copy))
+ result |= DragDropEffects.Copy;
+ if (d.HasFlag(NSDragOperation.Link))
+ result |= DragDropEffects.Link;
+ if (d.HasFlag(NSDragOperation.Move))
+ result |= DragDropEffects.Move;
+ return result;
+ }
+
+ public Point Location => new Point(_info.DraggingLocation.X, _info.DraggingLocation.Y);
+
+ public IEnumerable GetDataFormats()
+ {
+ return _info.DraggingPasteboard.Types.Select(NSTypeToWellknownType);
+ }
+
+ private string NSTypeToWellknownType(string type)
+ {
+ if (type == NSPasteboard.NSStringType)
+ return DataFormats.Text;
+ if (type == NSPasteboard.NSFilenamesType)
+ return DataFormats.FileNames;
+ return type;
+ }
+
+ public string GetText()
+ {
+ return _info.DraggingPasteboard.GetStringForType(NSPasteboard.NSStringType);
+ }
+
+ public IEnumerable GetFileNames()
+ {
+ using(var fileNames = (NSArray)_info.DraggingPasteboard.GetPropertyListForType(NSPasteboard.NSFilenamesType))
+ {
+ if (fileNames != null)
+ return NSArray.StringArrayFromHandle(fileNames.Handle);
+ }
+
+ return Enumerable.Empty();
+ }
+
+ public bool Contains(string dataFormat)
+ {
+ return GetDataFormats().Any(f => f == dataFormat);
+ }
+
+ public object Get(string dataFormat)
+ {
+ if (dataFormat == DataFormats.Text)
+ return GetText();
+ if (dataFormat == DataFormats.FileNames)
+ return GetFileNames();
+
+ return _info.DraggingPasteboard.GetDataForType(dataFormat).ToArray();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs b/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs
index 5907459459..ba45ad8403 100644
--- a/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs
+++ b/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs
@@ -35,7 +35,8 @@ namespace Avalonia.MonoMac
.Bind().ToSingleton()
.Bind().ToSingleton()
.Bind().ToConstant(s_renderLoop)
- .Bind().ToConstant(PlatformThreadingInterface.Instance);
+ .Bind().ToConstant(PlatformThreadingInterface.Instance)
+ /*.Bind().ToTransient()*/;
}
public static void Initialize()
diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
index a655bc1ec5..db7f29f05b 100644
--- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
+++ b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
@@ -18,6 +18,7 @@ namespace Avalonia.MonoMac
{
public TopLevelView View { get; }
private readonly IMouseDevice _mouse = AvaloniaLocator.Current.GetService();
+ private readonly IDragDropDevice _dragDevice = AvaloniaLocator.Current.GetService();
protected TopLevelImpl()
{
View = new TopLevelView(this);
@@ -53,6 +54,10 @@ namespace Avalonia.MonoMac
_tl = tl;
_mouse = AvaloniaLocator.Current.GetService();
_keyboard = AvaloniaLocator.Current.GetService();
+
+ RegisterForDraggedTypes(new string[] {
+ "public.data" // register for any kind of data.
+ });
}
protected override void Dispose(bool disposing)
@@ -149,6 +154,48 @@ namespace Avalonia.MonoMac
UpdateCursor();
}
+ private NSDragOperation SendRawDragEvent(NSDraggingInfo sender, RawDragEventType type)
+ {
+ Action input = _tl.Input;
+ IDragDropDevice dragDevice = _tl._dragDevice;
+ IInputRoot root = _tl?.InputRoot;
+ if (root == null || dragDevice == null || input == null)
+ return NSDragOperation.None;
+
+ 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);
+ input(args);
+ return DraggingInfo.ConvertDragOperation(args.Effects);
+ }
+
+ public override NSDragOperation DraggingEntered(NSDraggingInfo sender)
+ {
+ return SendRawDragEvent(sender, RawDragEventType.DragEnter);
+ }
+
+ public override NSDragOperation DraggingUpdated(NSDraggingInfo sender)
+ {
+ return SendRawDragEvent(sender, RawDragEventType.DragOver);
+ }
+
+ public override void DraggingExited(NSDraggingInfo sender)
+ {
+ SendRawDragEvent(sender, RawDragEventType.DragLeave);
+ }
+
+ public override bool PrepareForDragOperation(NSDraggingInfo sender)
+ {
+ return SendRawDragEvent(sender, RawDragEventType.DragOver) != NSDragOperation.None;
+ }
+
+ public override bool PerformDragOperation(NSDraggingInfo sender)
+ {
+ return SendRawDragEvent(sender, RawDragEventType.Drop) != NSDragOperation.None;
+ }
+
+
public override void SetFrameSize(CGSize newSize)
{
lock (SyncRoot)
diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
index c76a5b5da5..124e33c5a3 100644
--- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
+++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
@@ -103,7 +103,7 @@ namespace Avalonia.Direct2D1
/// Converts a pen to a Direct2D stroke style.
///
/// The pen to convert.
- /// The render target.
+ /// The render target.
/// The Direct2D brush.
public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.Pen pen, SharpDX.Direct2D1.RenderTarget renderTarget)
{
@@ -114,7 +114,7 @@ namespace Avalonia.Direct2D1
/// Converts a pen to a Direct2D stroke style.
///
/// The pen to convert.
- /// The render target.
+ /// The factory associated with this resource.
/// The Direct2D brush.
public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.Pen pen, Factory factory)
{
@@ -127,13 +127,16 @@ namespace Avalonia.Direct2D1
EndCap = pen.EndLineCap.ToDirect2D(),
DashCap = pen.DashCap.ToDirect2D()
};
- var dashes = new float[0];
+ float[] dashes = null;
if (pen.DashStyle?.Dashes != null && pen.DashStyle.Dashes.Count > 0)
{
properties.DashStyle = DashStyle.Custom;
properties.DashOffset = (float)pen.DashStyle.Offset;
- dashes = pen.DashStyle?.Dashes.Select(x => (float)x).ToArray();
+ dashes = pen.DashStyle.Dashes.Select(x => (float)x).ToArray();
}
+
+ dashes = dashes ?? Array.Empty();
+
return new StrokeStyle(factory, properties, dashes);
}
diff --git a/src/Windows/Avalonia.Win32/ClipboardFormats.cs b/src/Windows/Avalonia.Win32/ClipboardFormats.cs
new file mode 100644
index 0000000000..5e0bbab975
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/ClipboardFormats.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+ static class ClipboardFormats
+ {
+ private const int MAX_FORMAT_NAME_LENGTH = 260;
+
+ class ClipboardFormat
+ {
+ public short Format { get; private set; }
+ public string Name { get; private set; }
+ public short[] Synthesized { get; private set; }
+
+ public ClipboardFormat(string name, short format, params short[] synthesized)
+ {
+ Format = format;
+ Name = name;
+ Synthesized = synthesized;
+ }
+ }
+
+ private static readonly List FormatList = new List()
+ {
+ new ClipboardFormat(DataFormats.Text, (short)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, (short)UnmanagedMethods.ClipboardFormat.CF_TEXT),
+ new ClipboardFormat(DataFormats.FileNames, (short)UnmanagedMethods.ClipboardFormat.CF_HDROP),
+ };
+
+
+ private static string QueryFormatName(short format)
+ {
+ StringBuilder sb = new StringBuilder(MAX_FORMAT_NAME_LENGTH);
+ if (UnmanagedMethods.GetClipboardFormatName(format, sb, sb.Capacity) > 0)
+ return sb.ToString();
+ return null;
+ }
+
+ public static string GetFormat(short format)
+ {
+ lock (FormatList)
+ {
+ var pd = FormatList.FirstOrDefault(f => f.Format == format || Array.IndexOf(f.Synthesized, format) >= 0);
+ if (pd == null)
+ {
+ string name = QueryFormatName(format);
+ if (string.IsNullOrEmpty(name))
+ name = string.Format("Unknown_Format_{0}", format);
+ pd = new ClipboardFormat(name, format);
+ FormatList.Add(pd);
+ }
+ return pd.Name;
+ }
+ }
+
+ public static short GetFormat(string format)
+ {
+ lock (FormatList)
+ {
+ var pd = FormatList.FirstOrDefault(f => StringComparer.OrdinalIgnoreCase.Equals(f.Name, format));
+ if (pd == null)
+ {
+ int id = UnmanagedMethods.RegisterClipboardFormat(format);
+ if (id == 0)
+ throw new Win32Exception();
+ pd = new ClipboardFormat(format, (short)id);
+ FormatList.Add(pd);
+ }
+ return pd.Format;
+ }
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/Windows/Avalonia.Win32/CursorFactory.cs b/src/Windows/Avalonia.Win32/CursorFactory.cs
index 0d529d6b91..fa2fbe4810 100644
--- a/src/Windows/Avalonia.Win32/CursorFactory.cs
+++ b/src/Windows/Avalonia.Win32/CursorFactory.cs
@@ -9,6 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Platform;
+using System.Runtime.InteropServices;
namespace Avalonia.Win32
{
@@ -20,6 +21,27 @@ namespace Avalonia.Win32
{
}
+ static CursorFactory()
+ {
+ LoadModuleCursor(StandardCursorType.DragMove, "ole32.dll", 2);
+ LoadModuleCursor(StandardCursorType.DragCopy, "ole32.dll", 3);
+ LoadModuleCursor(StandardCursorType.DragLink, "ole32.dll", 4);
+ }
+
+ private static void LoadModuleCursor(StandardCursorType cursorType, string module, int id)
+ {
+ IntPtr mh = UnmanagedMethods.GetModuleHandle(module);
+ if (mh != IntPtr.Zero)
+ {
+ IntPtr cursor = UnmanagedMethods.LoadCursor(mh, new IntPtr(id));
+ if (cursor != IntPtr.Zero)
+ {
+ PlatformHandle phCursor = new PlatformHandle(cursor, PlatformConstants.CursorHandleType);
+ Cache.Add(cursorType, phCursor);
+ }
+ }
+ }
+
private static readonly Dictionary CursorTypeMapping = new Dictionary
{
@@ -47,6 +69,11 @@ namespace Avalonia.Win32
//Using SizeNorthEastSouthWest
{StandardCursorType.TopRightCorner, 32643},
{StandardCursorType.BottomLeftCorner, 32643},
+
+ // Fallback, should have been loaded from ole32.dll
+ {StandardCursorType.DragMove, 32516},
+ {StandardCursorType.DragCopy, 32516},
+ {StandardCursorType.DragLink, 32516},
};
private static readonly Dictionary Cache =
diff --git a/src/Windows/Avalonia.Win32/DataObject.cs b/src/Windows/Avalonia.Win32/DataObject.cs
new file mode 100644
index 0000000000..34867765e5
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DataObject.cs
@@ -0,0 +1,361 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Win32.Interop;
+using IDataObject = Avalonia.Input.IDataObject;
+using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+
+namespace Avalonia.Win32
+{
+ class DataObject : IDataObject, IOleDataObject
+ {
+ // Compatibility with WinForms + WPF...
+ internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
+
+ class FormatEnumerator : IEnumFORMATETC
+ {
+ private FORMATETC[] _formats;
+ private int _current;
+
+ private FormatEnumerator(FORMATETC[] formats, int current)
+ {
+ _formats = formats;
+ _current = current;
+ }
+
+ public FormatEnumerator(IDataObject dataobj)
+ {
+ _formats = dataobj.GetDataFormats().Select(ConvertToFormatEtc).ToArray();
+ _current = 0;
+ }
+
+ private FORMATETC ConvertToFormatEtc(string aFormatName)
+ {
+ FORMATETC result = default(FORMATETC);
+ result.cfFormat = ClipboardFormats.GetFormat(aFormatName);
+ result.dwAspect = DVASPECT.DVASPECT_CONTENT;
+ result.ptd = IntPtr.Zero;
+ result.lindex = -1;
+ result.tymed = TYMED.TYMED_HGLOBAL;
+ return result;
+ }
+
+ public void Clone(out IEnumFORMATETC newEnum)
+ {
+ newEnum = new FormatEnumerator(_formats, _current);
+ }
+
+ public int Next(int celt, FORMATETC[] rgelt, int[] pceltFetched)
+ {
+ if (rgelt == null)
+ return unchecked((int)UnmanagedMethods.HRESULT.E_INVALIDARG);
+
+ int i = 0;
+ while (i < celt && _current < _formats.Length)
+ {
+ rgelt[i] = _formats[_current];
+ _current++;
+ i++;
+ }
+ if (pceltFetched != null)
+ pceltFetched[0] = i;
+
+ if (i != celt)
+ return unchecked((int)UnmanagedMethods.HRESULT.S_FALSE);
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+
+ public int Reset()
+ {
+ _current = 0;
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+
+ public int Skip(int celt)
+ {
+ _current += Math.Min(celt, int.MaxValue - _current);
+ if (_current >= _formats.Length)
+ return unchecked((int)UnmanagedMethods.HRESULT.S_FALSE);
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+ }
+
+ private const int DV_E_TYMED = unchecked((int)0x80040069);
+ private const int DV_E_DVASPECT = unchecked((int)0x8004006B);
+ private const int DV_E_FORMATETC = unchecked((int)0x80040064);
+ private const int OLE_E_ADVISENOTSUPPORTED = unchecked((int)0x80040003);
+ private const int STG_E_MEDIUMFULL = unchecked((int)0x80030070);
+ private const int GMEM_ZEROINIT = 0x0040;
+ private const int GMEM_MOVEABLE = 0x0002;
+
+
+ IDataObject _wrapped;
+
+ public DataObject(IDataObject wrapped)
+ {
+ _wrapped = wrapped;
+ }
+
+ #region IDataObject
+ bool IDataObject.Contains(string dataFormat)
+ {
+ return _wrapped.Contains(dataFormat);
+ }
+
+ IEnumerable IDataObject.GetDataFormats()
+ {
+ return _wrapped.GetDataFormats();
+ }
+
+ IEnumerable IDataObject.GetFileNames()
+ {
+ return _wrapped.GetFileNames();
+ }
+
+ string IDataObject.GetText()
+ {
+ return _wrapped.GetText();
+ }
+
+ object IDataObject.Get(string dataFormat)
+ {
+ return _wrapped.Get(dataFormat);
+ }
+ #endregion
+
+ #region IOleDataObject
+
+ int IOleDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection)
+ {
+ if (_wrapped is IOleDataObject ole)
+ return ole.DAdvise(ref pFormatetc, advf, adviseSink, out connection);
+ connection = 0;
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ void IOleDataObject.DUnadvise(int connection)
+ {
+ if (_wrapped is IOleDataObject ole)
+ ole.DUnadvise(connection);
+ Marshal.ThrowExceptionForHR(OLE_E_ADVISENOTSUPPORTED);
+ }
+
+ int IOleDataObject.EnumDAdvise(out IEnumSTATDATA enumAdvise)
+ {
+ if (_wrapped is IOleDataObject ole)
+ return ole.EnumDAdvise(out enumAdvise);
+
+ enumAdvise = null;
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ IEnumFORMATETC IOleDataObject.EnumFormatEtc(DATADIR direction)
+ {
+ if (_wrapped is IOleDataObject ole)
+ return ole.EnumFormatEtc(direction);
+ if (direction == DATADIR.DATADIR_GET)
+ return new FormatEnumerator(_wrapped);
+ throw new NotSupportedException();
+ }
+
+ int IOleDataObject.GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut)
+ {
+ if (_wrapped is IOleDataObject ole)
+ return ole.GetCanonicalFormatEtc(ref formatIn, out formatOut);
+
+ formatOut = new FORMATETC();
+ formatOut.ptd = IntPtr.Zero;
+ return unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL);
+ }
+
+ void IOleDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium)
+ {
+ if (_wrapped is IOleDataObject ole)
+ {
+ ole.GetData(ref format, out medium);
+ return;
+ }
+ if(!format.tymed.HasFlag(TYMED.TYMED_HGLOBAL))
+ Marshal.ThrowExceptionForHR(DV_E_TYMED);
+
+ if (format.dwAspect != DVASPECT.DVASPECT_CONTENT)
+ Marshal.ThrowExceptionForHR(DV_E_DVASPECT);
+
+ string fmt = ClipboardFormats.GetFormat(format.cfFormat);
+ if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt))
+ Marshal.ThrowExceptionForHR(DV_E_FORMATETC);
+
+ medium = default(STGMEDIUM);
+ medium.tymed = TYMED.TYMED_HGLOBAL;
+ int result = WriteDataToHGlobal(fmt, ref medium.unionmember);
+ Marshal.ThrowExceptionForHR(result);
+ }
+
+ void IOleDataObject.GetDataHere(ref FORMATETC format, ref STGMEDIUM medium)
+ {
+ if (_wrapped is IOleDataObject ole)
+ {
+ ole.GetDataHere(ref format, ref medium);
+ return;
+ }
+
+ if (medium.tymed != TYMED.TYMED_HGLOBAL || !format.tymed.HasFlag(TYMED.TYMED_HGLOBAL))
+ Marshal.ThrowExceptionForHR(DV_E_TYMED);
+
+ if (format.dwAspect != DVASPECT.DVASPECT_CONTENT)
+ Marshal.ThrowExceptionForHR(DV_E_DVASPECT);
+
+ string fmt = ClipboardFormats.GetFormat(format.cfFormat);
+ if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt))
+ Marshal.ThrowExceptionForHR(DV_E_FORMATETC);
+
+ if (medium.unionmember == IntPtr.Zero)
+ Marshal.ThrowExceptionForHR(STG_E_MEDIUMFULL);
+
+ int result = WriteDataToHGlobal(fmt, ref medium.unionmember);
+ Marshal.ThrowExceptionForHR(result);
+ }
+
+ int IOleDataObject.QueryGetData(ref FORMATETC format)
+ {
+ if (_wrapped is IOleDataObject ole)
+ return ole.QueryGetData(ref format);
+ if (format.dwAspect != DVASPECT.DVASPECT_CONTENT)
+ return DV_E_DVASPECT;
+ if (!format.tymed.HasFlag(TYMED.TYMED_HGLOBAL))
+ return DV_E_TYMED;
+
+ string dataFormat = ClipboardFormats.GetFormat(format.cfFormat);
+ if (!string.IsNullOrEmpty(dataFormat) && _wrapped.Contains(dataFormat))
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ return DV_E_FORMATETC;
+ }
+
+ void IOleDataObject.SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release)
+ {
+ if (_wrapped is IOleDataObject ole)
+ {
+ ole.SetData(ref formatIn, ref medium, release);
+ return;
+ }
+ Marshal.ThrowExceptionForHR(unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL));
+ }
+
+ private int WriteDataToHGlobal(string dataFormat, ref IntPtr hGlobal)
+ {
+ object data = _wrapped.Get(dataFormat);
+ if (dataFormat == DataFormats.Text || data is string)
+ return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data));
+ if (dataFormat == DataFormats.FileNames && data is IEnumerable files)
+ return WriteFileListToHGlobal(ref hGlobal, files);
+ if (data is Stream stream)
+ {
+ byte[] buffer = new byte[stream.Length - stream.Position];
+ stream.Read(buffer, 0, buffer.Length);
+ return WriteBytesToHGlobal(ref hGlobal, buffer);
+ }
+ if (data is IEnumerable bytes)
+ {
+ var byteArr = bytes is byte[] ? (byte[])bytes : bytes.ToArray();
+ return WriteBytesToHGlobal(ref hGlobal, byteArr);
+ }
+ return WriteBytesToHGlobal(ref hGlobal, SerializeObject(data));
+ }
+
+ private byte[] SerializeObject(object data)
+ {
+ using (var ms = new MemoryStream())
+ {
+ ms.Write(SerializedObjectGUID, 0, SerializedObjectGUID.Length);
+ BinaryFormatter binaryFormatter = new BinaryFormatter();
+ binaryFormatter.Serialize(ms, data);
+ return ms.ToArray();
+ }
+ }
+
+ private int WriteBytesToHGlobal(ref IntPtr hGlobal, byte[] data)
+ {
+ int required = data.Length;
+ if (hGlobal == IntPtr.Zero)
+ hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, required);
+
+ long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+ if (required > available)
+ return STG_E_MEDIUMFULL;
+
+ IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+ try
+ {
+ Marshal.Copy(data, 0, ptr, data.Length);
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+ finally
+ {
+ UnmanagedMethods.GlobalUnlock(hGlobal);
+ }
+ }
+
+ private int WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable files)
+ {
+ if (!files?.Any() ?? false)
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+
+ char[] filesStr = (string.Join("\0", files) + "\0\0").ToCharArray();
+ _DROPFILES df = new _DROPFILES();
+ df.pFiles = Marshal.SizeOf<_DROPFILES>();
+ df.fWide = true;
+
+ int required = (filesStr.Length * sizeof(char)) + Marshal.SizeOf<_DROPFILES>();
+ if (hGlobal == IntPtr.Zero)
+ hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, required);
+
+ long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+ if (required > available)
+ return STG_E_MEDIUMFULL;
+
+ IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+ try
+ {
+ Marshal.StructureToPtr(df, ptr, false);
+
+ Marshal.Copy(filesStr, 0, ptr + Marshal.SizeOf<_DROPFILES>(), filesStr.Length);
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+ finally
+ {
+ UnmanagedMethods.GlobalUnlock(hGlobal);
+ }
+ }
+
+ private int WriteStringToHGlobal(ref IntPtr hGlobal, string data)
+ {
+ int required = (data.Length + 1) * sizeof(char);
+ if (hGlobal == IntPtr.Zero)
+ hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, required);
+
+ long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+ if (required > available)
+ return STG_E_MEDIUMFULL;
+
+ IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+ try
+ {
+ char[] chars = (data + '\0').ToCharArray();
+ Marshal.Copy(chars, 0, ptr, chars.Length);
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+ finally
+ {
+ UnmanagedMethods.GlobalUnlock(hGlobal);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/DragSource.cs b/src/Windows/Avalonia.Win32/DragSource.cs
new file mode 100644
index 0000000000..ea124e5f29
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DragSource.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Threading;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+ class DragSource : IPlatformDragSource
+ {
+ public Task DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+ {
+ Dispatcher.UIThread.VerifyAccess();
+
+ OleDragSource src = new OleDragSource();
+ DataObject dataObject = new DataObject(data);
+ int allowed = (int)OleDropTarget.ConvertDropEffect(allowedEffects);
+
+ int[] finalEffect = new int[1];
+ UnmanagedMethods.DoDragDrop(dataObject, src, allowed, finalEffect);
+
+ return Task.FromResult(OleDropTarget.ConvertDropEffect((DropEffect)finalEffect[0]));}
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index f13dd3272c..aa86ab0f8d 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -5,6 +5,7 @@ using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
using System.Text;
// ReSharper disable InconsistentNaming
@@ -951,6 +952,32 @@ namespace Avalonia.Win32.Interop
[DllImport("msvcrt.dll", EntryPoint="memcpy", SetLastError = false, CallingConvention=CallingConvention.Cdecl)]
public static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, UIntPtr count);
+ [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+ public static extern HRESULT RegisterDragDrop(IntPtr hwnd, IDropTarget target);
+
+ [DllImport("ole32.dll", EntryPoint = "OleInitialize")]
+ public static extern HRESULT OleInitialize(IntPtr val);
+
+ [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+ internal static extern void ReleaseStgMedium(ref STGMEDIUM medium);
+
+ [DllImport("user32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetClipboardFormatName(int format, StringBuilder lpString, int cchMax);
+
+ [DllImport("user32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int RegisterClipboardFormat(string format);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)]
+ public static extern IntPtr GlobalSize(IntPtr hGlobal);
+
+ [DllImport("shell32.dll", BestFitMapping = false, CharSet = CharSet.Auto)]
+ public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
+
+ [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
+ public static extern void DoDragDrop(IDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect);
+
+
+
public enum MONITOR
{
MONITOR_DEFAULTTONULL = 0x00000000,
@@ -990,10 +1017,28 @@ namespace Avalonia.Win32.Interop
MDT_DEFAULT = MDT_EFFECTIVE_DPI
}
- public enum ClipboardFormat
+ public enum ClipboardFormat
{
+ ///
+ /// Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data. Use this format for ANSI text.
+ ///
CF_TEXT = 1,
- CF_UNICODETEXT = 13
+ ///
+ /// A handle to a bitmap
+ ///
+ CF_BITMAP = 2,
+ ///
+ /// A memory object containing a BITMAPINFO structure followed by the bitmap bits.
+ ///
+ CF_DIB = 3,
+ ///
+ /// Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.
+ ///
+ CF_UNICODETEXT = 13,
+ ///
+ /// A handle to type HDROP that identifies a list of files.
+ ///
+ CF_HDROP = 15,
}
public struct MSG
@@ -1136,7 +1181,9 @@ namespace Avalonia.Win32.Interop
S_FALSE = 0x0001,
S_OK = 0x0000,
E_INVALIDARG = 0x80070057,
- E_OUTOFMEMORY = 0x8007000E
+ E_OUTOFMEMORY = 0x8007000E,
+ E_NOTIMPL = 0x80004001,
+ E_UNEXPECTED = 0x8000FFFF,
}
public enum Icons
@@ -1300,4 +1347,53 @@ namespace Avalonia.Win32.Interop
uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
}
+
+ [Flags]
+ internal enum DropEffect : int
+ {
+ None = 0,
+ Copy = 1,
+ Move = 2,
+ Link = 4,
+ Scroll = -2147483648,
+ }
+
+
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("00000122-0000-0000-C000-000000000046")]
+ internal interface IDropTarget
+ {
+ [PreserveSig]
+ UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+ [PreserveSig]
+ UnmanagedMethods.HRESULT DragOver([MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+ [PreserveSig]
+ UnmanagedMethods.HRESULT DragLeave();
+ [PreserveSig]
+ UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("00000121-0000-0000-C000-000000000046")]
+ internal interface IDropSource
+ {
+ [PreserveSig]
+ int QueryContinueDrag(int fEscapePressed, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState);
+ [PreserveSig]
+ int GiveFeedback([MarshalAs(UnmanagedType.U4)] [In] int dwEffect);
+ }
+
+
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ internal struct _DROPFILES
+ {
+ public Int32 pFiles;
+ public Int32 X;
+ public Int32 Y;
+ public bool fNC;
+ public bool fWide;
+ }
}
diff --git a/src/Windows/Avalonia.Win32/OleContext.cs b/src/Windows/Avalonia.Win32/OleContext.cs
new file mode 100644
index 0000000000..085c0f8ea9
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/OleContext.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Threading;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+ class OleContext
+ {
+ private static OleContext fCurrent;
+
+ internal static OleContext Current
+ {
+ get
+ {
+ if (!IsValidOleThread())
+ return null;
+
+ if (fCurrent == null)
+ fCurrent = new OleContext();
+ return fCurrent;
+ }
+ }
+
+
+ private OleContext()
+ {
+ if (UnmanagedMethods.OleInitialize(IntPtr.Zero) != UnmanagedMethods.HRESULT.S_OK)
+ throw new SystemException("Failed to initialize OLE");
+ }
+
+ private static bool IsValidOleThread()
+ {
+ return Dispatcher.UIThread.CheckAccess() &&
+ Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
+ }
+
+ internal bool RegisterDragDrop(IPlatformHandle hwnd, IDropTarget target)
+ {
+ if (hwnd?.HandleDescriptor != "HWND" || target == null)
+ return false;
+
+ return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, target) == UnmanagedMethods.HRESULT.S_OK;
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/OleDataObject.cs b/src/Windows/Avalonia.Win32/OleDataObject.cs
new file mode 100644
index 0000000000..85d1daadeb
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/OleDataObject.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Win32.Interop;
+using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
+
+namespace Avalonia.Win32
+{
+ class OleDataObject : Avalonia.Input.IDataObject
+ {
+ private IDataObject _wrapped;
+
+ public OleDataObject(IDataObject wrapped)
+ {
+ _wrapped = wrapped;
+ }
+
+ public bool Contains(string dataFormat)
+ {
+ return GetDataFormatsCore().Any(df => StringComparer.OrdinalIgnoreCase.Equals(df, dataFormat));
+ }
+
+ public IEnumerable GetDataFormats()
+ {
+ return GetDataFormatsCore().Distinct();
+ }
+
+ public string GetText()
+ {
+ return GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT) as string;
+ }
+
+ public IEnumerable GetFileNames()
+ {
+ return GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT) as IEnumerable;
+ }
+
+ public object Get(string dataFormat)
+ {
+ return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT);
+ }
+
+ private object GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
+ {
+ FORMATETC formatEtc = new FORMATETC();
+ formatEtc.cfFormat = ClipboardFormats.GetFormat(format);
+ formatEtc.dwAspect = aspect;
+ formatEtc.lindex = -1;
+ formatEtc.tymed = TYMED.TYMED_HGLOBAL;
+ if (_wrapped.QueryGetData(ref formatEtc) == 0)
+ {
+ _wrapped.GetData(ref formatEtc, out STGMEDIUM medium);
+ try
+ {
+ if (medium.unionmember != IntPtr.Zero && medium.tymed == TYMED.TYMED_HGLOBAL)
+ {
+ if (format == DataFormats.Text)
+ return ReadStringFromHGlobal(medium.unionmember);
+ if (format == DataFormats.FileNames)
+ return ReadFileNamesFromHGlobal(medium.unionmember);
+
+ byte[] data = ReadBytesFromHGlobal(medium.unionmember);
+
+ if (IsSerializedObject(data))
+ {
+ using (var ms = new MemoryStream(data))
+ {
+ ms.Position = DataObject.SerializedObjectGUID.Length;
+ BinaryFormatter binaryFormatter = new BinaryFormatter();
+ return binaryFormatter.Deserialize(ms);
+ }
+ }
+ return data;
+ }
+ }
+ finally
+ {
+ UnmanagedMethods.ReleaseStgMedium(ref medium);
+ }
+ }
+ return null;
+ }
+
+ private bool IsSerializedObject(byte[] data)
+ {
+ if (data.Length < DataObject.SerializedObjectGUID.Length)
+ return false;
+ for (int i = 0; i < DataObject.SerializedObjectGUID.Length; i++)
+ if (data[i] != DataObject.SerializedObjectGUID[i])
+ return false;
+ return true;
+ }
+
+ private static IEnumerable ReadFileNamesFromHGlobal(IntPtr hGlobal)
+ {
+ List files = new List();
+ int fileCount = UnmanagedMethods.DragQueryFile(hGlobal, -1, null, 0);
+ if (fileCount > 0)
+ {
+ for (int i = 0; i < fileCount; i++)
+ {
+ int pathLen = UnmanagedMethods.DragQueryFile(hGlobal, i, null, 0);
+ StringBuilder sb = new StringBuilder(pathLen+1);
+
+ if (UnmanagedMethods.DragQueryFile(hGlobal, i, sb, sb.Capacity) == pathLen)
+ {
+ files.Add(sb.ToString());
+ }
+ }
+ }
+ return files;
+ }
+
+ private static string ReadStringFromHGlobal(IntPtr hGlobal)
+ {
+ IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+ try
+ {
+ return Marshal.PtrToStringAuto(ptr);
+ }
+ finally
+ {
+ UnmanagedMethods.GlobalUnlock(hGlobal);
+ }
+ }
+
+ private static byte[] ReadBytesFromHGlobal(IntPtr hGlobal)
+ {
+ IntPtr source = UnmanagedMethods.GlobalLock(hGlobal);
+ try
+ {
+ int size = (int)UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+ byte[] data = new byte[size];
+ Marshal.Copy(source, data, 0, size);
+ return data;
+ }
+ finally
+ {
+ UnmanagedMethods.GlobalUnlock(hGlobal);
+ }
+ }
+
+ private IEnumerable GetDataFormatsCore()
+ {
+ var enumFormat = _wrapped.EnumFormatEtc(DATADIR.DATADIR_GET);
+ if (enumFormat != null)
+ {
+ enumFormat.Reset();
+ FORMATETC[] formats = new FORMATETC[1];
+ int[] fetched = { 1 };
+ while (fetched[0] > 0)
+ {
+ fetched[0] = 0;
+ if (enumFormat.Next(1, formats, fetched) == 0 && fetched[0] > 0)
+ {
+ if (formats[0].ptd != IntPtr.Zero)
+ Marshal.FreeCoTaskMem(formats[0].ptd);
+
+ yield return ClipboardFormats.GetFormat(formats[0].cfFormat);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Windows/Avalonia.Win32/OleDragSource.cs b/src/Windows/Avalonia.Win32/OleDragSource.cs
new file mode 100644
index 0000000000..522014abc0
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/OleDragSource.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+ class OleDragSource : IDropSource
+ {
+ private const int DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102;
+ 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 };
+
+ public int QueryContinueDrag(int fEscapePressed, int grfKeyState)
+ {
+ if (fEscapePressed != 0)
+ return DRAGDROP_S_CANCEL;
+
+ int pressedMouseButtons = MOUSE_BUTTONS.Where(mb => (grfKeyState & mb) == mb).Count();
+
+ if (pressedMouseButtons >= 2)
+ return DRAGDROP_S_CANCEL;
+ if (pressedMouseButtons == 0)
+ return DRAGDROP_S_DROP;
+
+ return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+ }
+
+ public int GiveFeedback(int dwEffect)
+ {
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs
new file mode 100644
index 0000000000..500c03e317
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs
@@ -0,0 +1,160 @@
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Win32.Interop;
+using IDataObject = Avalonia.Input.IDataObject;
+using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
+
+namespace Avalonia.Win32
+{
+ class OleDropTarget : IDropTarget
+ {
+ private readonly IInputElement _target;
+ private readonly ITopLevelImpl _tl;
+ private readonly IDragDropDevice _dragDevice;
+
+ private IDataObject _currentDrag = null;
+
+ public OleDropTarget(ITopLevelImpl tl, IInputElement target)
+ {
+ _dragDevice = AvaloniaLocator.Current.GetService();
+ _tl = tl;
+ _target = target;
+ }
+
+ public static DropEffect ConvertDropEffect(DragDropEffects operation)
+ {
+ DropEffect result = DropEffect.None;
+ if (operation.HasFlag(DragDropEffects.Copy))
+ result |= DropEffect.Copy;
+ if (operation.HasFlag(DragDropEffects.Move))
+ result |= DropEffect.Move;
+ if (operation.HasFlag(DragDropEffects.Link))
+ result |= DropEffect.Link;
+ return result;
+ }
+
+ public static DragDropEffects ConvertDropEffect(DropEffect effect)
+ {
+ DragDropEffects result = DragDropEffects.None;
+ if (effect.HasFlag(DropEffect.Copy))
+ result |= DragDropEffects.Copy;
+ if (effect.HasFlag(DropEffect.Move))
+ result |= DragDropEffects.Move;
+ if (effect.HasFlag(DropEffect.Link))
+ result |= DragDropEffects.Link;
+ return result;
+ }
+
+ UnmanagedMethods.HRESULT IDropTarget.DragEnter(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect)
+ {
+ var dispatch = _tl?.Input;
+ if (dispatch == null)
+ {
+ pdwEffect = DropEffect.None;
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+ _currentDrag = pDataObj as IDataObject;
+ if (_currentDrag == null)
+ _currentDrag = new OleDataObject(pDataObj);
+ var args = new RawDragEvent(
+ _dragDevice,
+ RawDragEventType.DragEnter,
+ _target,
+ GetDragLocation(pt),
+ _currentDrag,
+ ConvertDropEffect(pdwEffect)
+ );
+ dispatch(args);
+ pdwEffect = ConvertDropEffect(args.Effects);
+
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+
+ UnmanagedMethods.HRESULT IDropTarget.DragOver(int grfKeyState, long pt, ref DropEffect pdwEffect)
+ {
+ var dispatch = _tl?.Input;
+ if (dispatch == null)
+ {
+ pdwEffect = DropEffect.None;
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+
+ var args = new RawDragEvent(
+ _dragDevice,
+ RawDragEventType.DragOver,
+ _target,
+ GetDragLocation(pt),
+ _currentDrag,
+ ConvertDropEffect(pdwEffect)
+ );
+ dispatch(args);
+ pdwEffect = ConvertDropEffect(args.Effects);
+
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+
+ UnmanagedMethods.HRESULT IDropTarget.DragLeave()
+ {
+ try
+ {
+ _tl?.Input(new RawDragEvent(
+ _dragDevice,
+ RawDragEventType.DragLeave,
+ _target,
+ default(Point),
+ null,
+ DragDropEffects.None
+ ));
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+ finally
+ {
+ _currentDrag = null;
+ }
+ }
+
+ UnmanagedMethods.HRESULT IDropTarget.Drop(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect)
+ {
+ try
+ {
+ var dispatch = _tl?.Input;
+ if (dispatch == null)
+ {
+ pdwEffect = DropEffect.None;
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+
+ _currentDrag = pDataObj as IDataObject;
+ if (_currentDrag == null)
+ _currentDrag= new OleDataObject(pDataObj);
+
+ var args = new RawDragEvent(
+ _dragDevice,
+ RawDragEventType.Drop,
+ _target,
+ GetDragLocation(pt),
+ _currentDrag,
+ ConvertDropEffect(pdwEffect)
+ );
+ dispatch(args);
+ pdwEffect = ConvertDropEffect(args.Effects);
+
+ return UnmanagedMethods.HRESULT.S_OK;
+ }
+ finally
+ {
+ _currentDrag = null;
+ }
+ }
+
+ private Point GetDragLocation(long dragPoint)
+ {
+ int x = (int)dragPoint;
+ int y = (int)(dragPoint >> 32);
+
+ Point screenPt = new Point(x, y);
+ return _target.PointToClient(screenPt);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs
index 113b2811dc..e1df24151d 100644
--- a/src/Windows/Avalonia.Win32/ScreenImpl.cs
+++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs
@@ -2,16 +2,9 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
-using System.Linq;
-using Avalonia.Controls;
using Avalonia.Platform;
-using Avalonia.Utilities;
using static Avalonia.Win32.Interop.UnmanagedMethods;
-#if NETSTANDARD
-using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception;
-#endif
-
namespace Avalonia.Win32
{
public class ScreenImpl : IScreenImpl
diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs
index 4e1ba618a8..95077f82a1 100644
--- a/src/Windows/Avalonia.Win32/Win32Platform.cs
+++ b/src/Windows/Avalonia.Win32/Win32Platform.cs
@@ -1,27 +1,23 @@
// 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 Avalonia.Input.Platform;
using System;
using System.Collections.Generic;
-using System.Reactive.Disposables;
+using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using System.Threading;
+using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Input;
+using Avalonia.Input.Platform;
using Avalonia.Platform;
-using Avalonia.Win32.Input;
-using Avalonia.Win32.Interop;
-using Avalonia.Controls;
using Avalonia.Rendering;
using Avalonia.Threading;
-using System.IO;
-#if NETSTANDARD
-using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception;
-#else
-using System.ComponentModel;
-#endif
+using Avalonia.Win32.Input;
+using Avalonia.Win32.Interop;
namespace Avalonia
{
@@ -86,6 +82,9 @@ namespace Avalonia.Win32
.Bind().ToConstant(s_instance)
.Bind().ToConstant(s_instance);
+ if (OleContext.Current != null)
+ AvaloniaLocator.CurrentMutable.Bind().ToSingleton();
+
UseDeferredRendering = deferredRendering;
_uiThread = UnmanagedMethods.GetCurrentThreadId();
}
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index a67362d59f..bb3c4cf6e6 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -34,6 +34,7 @@ namespace Avalonia.Win32
private double _scaling = 1;
private WindowState _showWindowState;
private FramebufferManager _framebuffer;
+ private OleDropTarget _dropTarget;
#if USE_MANAGED_DRAG
private readonly ManagedWindowResizeDragHelper _managedDrag;
#endif
@@ -310,6 +311,7 @@ namespace Avalonia.Win32
public void SetInputRoot(IInputRoot inputRoot)
{
_owner = inputRoot;
+ CreateDropTarget();
}
public void SetTitle(string title)
@@ -699,6 +701,13 @@ namespace Avalonia.Win32
}
}
+ private void CreateDropTarget()
+ {
+ OleDropTarget odt = new OleDropTarget(this, _owner);
+ if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false)
+ _dropTarget = odt;
+ }
+
private Point DipFromLParam(IntPtr lParam)
{
return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling;
diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
index f5c0c6ec15..f42e0daf2a 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
@@ -58,7 +58,7 @@ namespace Avalonia.Markup.UnitTests.Data
[Fact]
public async Task Should_Convert_Get_String_To_Double()
{
- var data = new Class1 { StringValue = "5.6" };
+ var data = new Class1 { StringValue = $"{5.6}" };
var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double));
var result = await target.Take(1);
@@ -94,12 +94,12 @@ namespace Avalonia.Markup.UnitTests.Data
[Fact]
public void Should_Convert_Set_String_To_Double()
{
- var data = new Class1 { StringValue = (5.6).ToString() };
+ var data = new Class1 { StringValue = $"{5.6}" };
var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double));
target.OnNext(6.7);
- Assert.Equal((6.7).ToString(), data.StringValue);
+ Assert.Equal($"{6.7}", data.StringValue);
GC.KeepAlive(data);
}
@@ -111,7 +111,7 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string));
var result = await target.Take(1);
- Assert.Equal((5.6).ToString(), result);
+ Assert.Equal($"{5.6}", result);
GC.KeepAlive(data);
}
@@ -122,7 +122,7 @@ namespace Avalonia.Markup.UnitTests.Data
var data = new Class1 { DoubleValue = 5.6 };
var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string));
- target.OnNext("6.7");
+ target.OnNext($"{6.7}");
Assert.Equal(6.7, data.DoubleValue);
@@ -318,15 +318,15 @@ namespace Avalonia.Markup.UnitTests.Data
target.Subscribe(x => result.Add(x));
target.OnNext(1.2);
- target.OnNext("3.4");
+ target.OnNext($"{3.4}");
target.OnNext("bar");
Assert.Equal(
new[]
{
- new BindingNotification("5.6"),
- new BindingNotification("1.2"),
- new BindingNotification("3.4"),
+ new BindingNotification($"{5.6}"),
+ new BindingNotification($"{1.2}"),
+ new BindingNotification($"{3.4}"),
new BindingNotification(
new InvalidCastException("'bar' is not a valid number."),
BindingErrorType.Error)
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
index 9bee92cd7a..ac25b7ccbe 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
@@ -8,6 +8,7 @@ using Avalonia.Markup.Xaml.Data;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
+using Avalonia.Media.Immutable;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Portable.Xaml;
@@ -378,8 +379,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
var control = AvaloniaXamlLoader.Parse(xaml);
var bk = control.Background;
- Assert.IsType(bk);
- Assert.Equal(Colors.White, (bk as SolidColorBrush).Color);
+ Assert.IsType(bk);
+ Assert.Equal(Colors.White, (bk as ISolidColorBrush).Color);
}
[Fact]
@@ -515,7 +516,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.NotNull(brush);
- Assert.Equal(Colors.White, ((SolidColorBrush)brush).Color);
+ Assert.Equal(Colors.White, ((ISolidColorBrush)brush).Color);
style.TryGetResource("Double", out var d);
diff --git a/tests/Avalonia.Visuals.UnitTests/Media/BrushTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/BrushTests.cs
index ae88a94073..a6015c52e5 100644
--- a/tests/Avalonia.Visuals.UnitTests/Media/BrushTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Media/BrushTests.cs
@@ -12,7 +12,7 @@ namespace Avalonia.Visuals.UnitTests.Media
[Fact]
public void Parse_Parses_RGB_Hash_Brush()
{
- var result = (SolidColorBrush)Brush.Parse("#ff8844");
+ var result = (ISolidColorBrush)Brush.Parse("#ff8844");
Assert.Equal(0xff, result.Color.R);
Assert.Equal(0x88, result.Color.G);
@@ -23,7 +23,7 @@ namespace Avalonia.Visuals.UnitTests.Media
[Fact]
public void Parse_Parses_ARGB_Hash_Brush()
{
- var result = (SolidColorBrush)Brush.Parse("#40ff8844");
+ var result = (ISolidColorBrush)Brush.Parse("#40ff8844");
Assert.Equal(0xff, result.Color.R);
Assert.Equal(0x88, result.Color.G);
@@ -34,7 +34,7 @@ namespace Avalonia.Visuals.UnitTests.Media
[Fact]
public void Parse_Parses_Named_Brush_Lowercase()
{
- var result = (SolidColorBrush)Brush.Parse("red");
+ var result = (ISolidColorBrush)Brush.Parse("red");
Assert.Equal(0xff, result.Color.R);
Assert.Equal(0x00, result.Color.G);
@@ -45,7 +45,7 @@ namespace Avalonia.Visuals.UnitTests.Media
[Fact]
public void Parse_Parses_Named_Brush_Uppercase()
{
- var result = (SolidColorBrush)Brush.Parse("RED");
+ var result = (ISolidColorBrush)Brush.Parse("RED");
Assert.Equal(0xff, result.Color.R);
Assert.Equal(0x00, result.Color.G);
@@ -53,6 +53,16 @@ namespace Avalonia.Visuals.UnitTests.Media
Assert.Equal(0xff, result.Color.A);
}
+ [Fact]
+ public void Parse_ToString_Named_Brush_Roundtrip()
+ {
+ const string expectedName = "Red";
+ var brush = (ISolidColorBrush)Brush.Parse(expectedName);
+ var name = brush.ToString();
+
+ Assert.Equal(expectedName, name);
+ }
+
[Fact]
public void Parse_Hex_Value_Doesnt_Accept_Too_Few_Chars()
{
diff --git a/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs b/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs
index 8ba4f3b739..9f25dcd413 100644
--- a/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.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.Globalization;
using Xunit;
@@ -25,5 +26,12 @@ namespace Avalonia.Visuals.UnitTests
Assert.Equal(new RelativeRect(0.1, 0.2, 0.4, 0.7, RelativeUnit.Relative), result, Compare);
}
+
+ [Fact]
+ public void Parse_Should_Throw_Mixed_Values()
+ {
+ Assert.Throws(() =>
+ RelativeRect.Parse("10%, 20%, 40, 70%", CultureInfo.InvariantCulture));
+ }
}
}