Browse Source

Merge branch 'master' into master

pull/4589/head
Steven Kirk 6 years ago
committed by GitHub
parent
commit
b01fd5ffec
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      nukebuild/Build.cs
  2. 5
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  3. 58
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  4. 1
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  5. 8
      samples/RenderDemo/MainWindow.xaml
  6. 3
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  7. 48
      samples/RenderDemo/ViewModels/MainWindowViewModel.cs
  8. 3
      src/Avalonia.Base/ApiCompatBaseline.txt
  9. 17
      src/Avalonia.Base/AvaloniaProperty.cs
  10. 48
      src/Avalonia.Base/AvaloniaProperty`1.cs
  11. 17
      src/Avalonia.Base/DirectPropertyBase.cs
  12. 2
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  13. 2
      src/Avalonia.Controls.DataGrid/DataGridCell.cs
  14. 2
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  15. 2
      src/Avalonia.Controls.DataGrid/DataGridRow.cs
  16. 2
      src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
  17. 2
      src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
  18. 96
      src/Avalonia.Controls/AutoCompleteBox.cs
  19. 2
      src/Avalonia.Controls/Button.cs
  20. 2
      src/Avalonia.Controls/ButtonSpinner.cs
  21. 2
      src/Avalonia.Controls/Calendar/CalendarButton.cs
  22. 2
      src/Avalonia.Controls/Calendar/CalendarDayButton.cs
  23. 2
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  24. 2
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  25. 2
      src/Avalonia.Controls/Chrome/TitleBar.cs
  26. 2
      src/Avalonia.Controls/DataValidationErrors.cs
  27. 4
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  28. 4
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  29. 3
      src/Avalonia.Controls/Expander.cs
  30. 9
      src/Avalonia.Controls/IconElement.cs
  31. 2
      src/Avalonia.Controls/ItemsControl.cs
  32. 2
      src/Avalonia.Controls/ListBoxItem.cs
  33. 2
      src/Avalonia.Controls/MenuItem.cs
  34. 4
      src/Avalonia.Controls/Mixins/SelectableMixin.cs
  35. 2
      src/Avalonia.Controls/NativeMenu.Export.cs
  36. 2
      src/Avalonia.Controls/NativeMenuItem.cs
  37. 2
      src/Avalonia.Controls/Notifications/NotificationCard.cs
  38. 2
      src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
  39. 21
      src/Avalonia.Controls/PathIcon.cs
  40. 2
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  41. 4
      src/Avalonia.Controls/Primitives/AccessText.cs
  42. 3
      src/Avalonia.Controls/Primitives/IPopupHost.cs
  43. 2
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
  44. 2
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  45. 2
      src/Avalonia.Controls/Primitives/Thumb.cs
  46. 2
      src/Avalonia.Controls/Primitives/ToggleButton.cs
  47. 2
      src/Avalonia.Controls/Primitives/Track.cs
  48. 2
      src/Avalonia.Controls/ProgressBar.cs
  49. 2
      src/Avalonia.Controls/Slider.cs
  50. 7
      src/Avalonia.Controls/SplitView.cs
  51. 2
      src/Avalonia.Controls/TabItem.cs
  52. 7
      src/Avalonia.Controls/TextBlock.cs
  53. 2
      src/Avalonia.Controls/TextBox.cs
  54. 4
      src/Avalonia.Controls/ToggleSwitch.cs
  55. 2
      src/Avalonia.Controls/ToolTip.cs
  56. 2
      src/Avalonia.Controls/TreeViewItem.cs
  57. 2
      src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  58. 2
      src/Avalonia.Input/InputElement.cs
  59. 8
      src/Avalonia.Native/Avalonia.Native.csproj
  60. 8
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  61. 41
      src/Avalonia.Native/AvaloniaNativePlatformOpenGlInterface.cs
  62. 6
      src/Avalonia.Native/PopupImpl.cs
  63. 6
      src/Avalonia.Native/WindowImpl.cs
  64. 2
      src/Avalonia.Native/WindowImplBase.cs
  65. 1
      src/Avalonia.OpenGL/Angle/AngleEglInterface.cs
  66. 10
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  67. 192
      src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
  68. 2
      src/Avalonia.OpenGL/Egl/EglConsts.cs
  69. 69
      src/Avalonia.OpenGL/Egl/EglContext.cs
  70. 53
      src/Avalonia.OpenGL/Egl/EglDisplay.cs
  71. 2
      src/Avalonia.OpenGL/Egl/EglErrors.cs
  72. 54
      src/Avalonia.OpenGL/Egl/EglGlPlatformSurface.cs
  73. 47
      src/Avalonia.OpenGL/Egl/EglGlPlatformSurfaceBase.cs
  74. 2
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  75. 72
      src/Avalonia.OpenGL/Egl/EglPlatformOpenGlInterface.cs
  76. 11
      src/Avalonia.OpenGL/Egl/EglSurface.cs
  77. 43
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  78. 51
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  79. 13
      src/Avalonia.OpenGL/GlInterface.cs
  80. 2
      src/Avalonia.OpenGL/IGlContext.cs
  81. 2
      src/Avalonia.OpenGL/IOpenGlAwarePlatformRenderInterface.cs
  82. 13
      src/Avalonia.OpenGL/IPlatformOpenGlInterface.cs
  83. 8
      src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs
  84. 17
      src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs
  85. 13
      src/Avalonia.OpenGL/Imaging/IOpenGlTextureBitmapImpl.cs
  86. 34
      src/Avalonia.OpenGL/Imaging/OpenGlBitmap.cs
  87. 1
      src/Avalonia.OpenGL/OpenGlException.cs
  88. 2
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurface.cs
  89. 2
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs
  90. 2
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderingSession.cs
  91. 18
      src/Avalonia.Styling/Controls/Metadata/PseudoClassesAttribute.cs
  92. 3
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  93. 3
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  94. 3
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  95. 17
      src/Avalonia.Themes.Default/PathIcon.xaml
  96. 2
      src/Avalonia.Themes.Fluent/Accents/Base.xaml
  97. 4
      src/Avalonia.Themes.Fluent/Button.xaml
  98. 3
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  99. 25
      src/Avalonia.Themes.Fluent/PathIcon.xaml
  100. 20
      src/Avalonia.Visuals/ApiCompatBaseline.txt

14
nukebuild/Build.cs

@ -138,9 +138,19 @@ partial class Build : NukeBuild
.SetWorkingDirectory(webappDir)
.SetCommand("dist"));
});
Target Compile => _ => _
Target CompileNative => _ => _
.DependsOn(Clean)
.OnlyWhenStatic(() => EnvironmentInfo.IsOsx)
.Executes(() =>
{
var project = $"{RootDirectory}/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/";
var args = $"-project {project} -configuration {Parameters.Configuration} CONFIGURATION_BUILD_DIR={RootDirectory}/Build/Products/Release";
ProcessTasks.StartProcess("xcodebuild", args).AssertZeroExitCode();
});
Target Compile => _ => _
.DependsOn(Clean, CompileNative)
.DependsOn(CompileHtmlPreviewer)
.Executes(async () =>
{

5
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -51,6 +51,11 @@
Width="200"
Margin="0,0,0,8"
FilterMode="None"/>
<TextBlock Text="Custom Autocomplete"/>
<AutoCompleteBox Name="CustomAutocompleteBox"
Width="200"
Margin="0,0,0,8"
FilterMode="None"/>
</StackPanel>
</StackPanel>
</StackPanel>

58
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -92,13 +92,28 @@ namespace ControlCatalog.Pages
}
public StateData[] States { get; private set; }
private LinkedList<string>[] BuildAllSentences()
{
return new string[]
{
"Hello world",
"No this is Patrick",
"Never gonna give you up",
"How does one patch KDE2 under FreeBSD"
}
.Select(x => new LinkedList<string>(x.Split(' ')))
.ToArray();
}
public LinkedList<string>[] Sentences { get; private set; }
public AutoCompleteBoxPage()
{
this.InitializeComponent();
States = BuildAllStates();
Sentences = BuildAllSentences();
foreach (AutoCompleteBox box in GetAllAutoCompleteBox())
foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox"))
{
box.Items = States;
}
@ -116,6 +131,11 @@ namespace ControlCatalog.Pages
var asyncBox = this.FindControl<AutoCompleteBox>("AsyncBox");
asyncBox.AsyncPopulator = PopulateAsync;
var customAutocompleteBox = this.FindControl<AutoCompleteBox>("CustomAutocompleteBox");
customAutocompleteBox.Items = Sentences.SelectMany(x => x);
customAutocompleteBox.TextFilter = LastWordContains;
customAutocompleteBox.TextSelector = AppendWord;
}
private IEnumerable<AutoCompleteBox> GetAllAutoCompleteBox()
{
@ -137,6 +157,42 @@ namespace ControlCatalog.Pages
.ToList();
}
private bool LastWordContains(string searchText, string item)
{
var words = searchText.Split(' ');
var options = Sentences.Select(x => x.First).ToArray();
for (var i = 0; i < words.Length; ++i)
{
var word = words[i];
for (var j = 0; j < options.Length; ++j)
{
var option = options[j];
if (option == null)
continue;
if (i == words.Length - 1)
{
options[j] = option.Value.ToLower().Contains(word.ToLower()) ? option : null;
}
else
{
options[j] = option.Value.Equals(word, StringComparison.InvariantCultureIgnoreCase) ? option.Next : null;
}
}
}
return options.Any(x => x != null && x.Value == item);
}
private string AppendWord(string text, string item)
{
string[] parts = text.Split(' ');
if (parts.Length == 0)
return item;
parts[parts.Length - 1] = item;
return string.Join(" ", parts);
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);

1
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Controls;
using Avalonia.Platform.Interop;
using Avalonia.Threading;
using static Avalonia.OpenGL.GlConsts;

8
samples/RenderDemo/MainWindow.xaml

@ -3,8 +3,8 @@
x:Class="RenderDemo.MainWindow"
Title="AvaloniaUI Rendering Test"
xmlns:pages="clr-namespace:RenderDemo.Pages"
Width="800"
Height="600">
Width="{Binding Width, Mode=TwoWay}"
Height="{Binding Height, Mode=TwoWay}">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Rendering">
@ -24,6 +24,10 @@
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Tests">
<MenuItem Header="Resize window"
Command="{Binding ResizeWindow}"/>
</MenuItem>
</Menu>
<TabControl Classes="sidebar">
<TabItem Header="Animations">

3
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -61,7 +61,6 @@ namespace RenderDemo.Pages
{
Foreground = Brushes.Black,
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices),
BaselineOrigin = new Point(0, -_glyphTypeface.Ascent * scale)
};
drawingGroup.Children.Add(glyphRunDrawing);
@ -69,7 +68,7 @@ namespace RenderDemo.Pages
var geometryDrawing = new GeometryDrawing
{
Pen = new Pen(Brushes.Black),
Geometry = new RectangleGeometry { Rect = glyphRunDrawing.GlyphRun.Bounds }
Geometry = new RectangleGeometry { Rect = new Rect(glyphRunDrawing.GlyphRun.Size) }
};
drawingGroup.Children.Add(geometryDrawing);

48
samples/RenderDemo/ViewModels/MainWindowViewModel.cs

@ -1,5 +1,6 @@
using System;
using System.Reactive;
using System.Reactive;
using System.Threading.Tasks;
using ReactiveUI;
namespace RenderDemo.ViewModels
@ -8,26 +9,61 @@ namespace RenderDemo.ViewModels
{
private bool drawDirtyRects = false;
private bool drawFps = true;
private double width = 800;
private double height = 600;
public MainWindowViewModel()
{
ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps);
ResizeWindow = ReactiveCommand.CreateFromTask(ResizeWindowAsync);
}
public bool DrawDirtyRects
{
get { return drawDirtyRects; }
set { this.RaiseAndSetIfChanged(ref drawDirtyRects, value); }
get => drawDirtyRects;
set => this.RaiseAndSetIfChanged(ref drawDirtyRects, value);
}
public bool DrawFps
{
get { return drawFps; }
set { this.RaiseAndSetIfChanged(ref drawFps, value); }
get => drawFps;
set => this.RaiseAndSetIfChanged(ref drawFps, value);
}
public double Width
{
get => width;
set => this.RaiseAndSetIfChanged(ref width, value);
}
public double Height
{
get => height;
set => this.RaiseAndSetIfChanged(ref height, value);
}
public ReactiveCommand<Unit, bool> ToggleDrawDirtyRects { get; }
public ReactiveCommand<Unit, bool> ToggleDrawFps { get; }
public ReactiveCommand<Unit, Unit> ResizeWindow { get; }
private async Task ResizeWindowAsync()
{
for (int i = 0; i < 30; i++)
{
Width += 10;
Height += 5;
await Task.Delay(10);
}
await Task.Delay(10);
for (int i = 0; i < 30; i++)
{
Width -= 10;
Height -= 5;
await Task.Delay(10);
}
}
}
}

3
src/Avalonia.Base/ApiCompatBaseline.txt

@ -0,0 +1,3 @@
Compat issues with assembly Avalonia.Base:
CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract.
Total Issues: 1

17
src/Avalonia.Base/AvaloniaProperty.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reactive.Subjects;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Utilities;
@ -18,7 +17,6 @@ namespace Avalonia
public static readonly object UnsetValue = new UnsetValueType();
private static int s_nextId;
private readonly Subject<AvaloniaPropertyChangedEventArgs> _changed;
private readonly PropertyMetadata _defaultMetadata;
private readonly Dictionary<Type, PropertyMetadata> _metadata;
private readonly Dictionary<Type, PropertyMetadata> _metadataCache = new Dictionary<Type, PropertyMetadata>();
@ -50,7 +48,6 @@ namespace Avalonia
throw new ArgumentException("'name' may not contain periods.");
}
_changed = new Subject<AvaloniaPropertyChangedEventArgs>();
_metadata = new Dictionary<Type, PropertyMetadata>();
Name = name;
@ -77,7 +74,6 @@ namespace Avalonia
Contract.Requires<ArgumentNullException>(source != null);
Contract.Requires<ArgumentNullException>(ownerType != null);
_changed = source._changed;
_metadata = new Dictionary<Type, PropertyMetadata>();
Name = source.Name;
@ -139,7 +135,7 @@ namespace Avalonia
/// An observable that is fired when this property changes on any
/// <see cref="AvaloniaObject"/> instance.
/// </value>
public IObservable<AvaloniaPropertyChangedEventArgs> Changed => _changed;
public IObservable<AvaloniaPropertyChangedEventArgs> Changed => GetChanged();
/// <summary>
/// Gets a method that gets called before and after the property starts being notified on an
@ -474,15 +470,6 @@ namespace Avalonia
public abstract void Accept<TData>(IAvaloniaPropertyVisitor<TData> vistor, ref TData data)
where TData : struct;
/// <summary>
/// Notifies the <see cref="Changed"/> observable.
/// </summary>
/// <param name="e">The observable arguments.</param>
internal void NotifyChanged(AvaloniaPropertyChangedEventArgs e)
{
_changed.OnNext(e);
}
/// <summary>
/// Routes an untyped ClearValue call to a typed call.
/// </summary>
@ -553,6 +540,8 @@ namespace Avalonia
_hasMetadataOverrides = true;
}
protected abstract IObservable<AvaloniaPropertyChangedEventArgs> GetChanged();
private PropertyMetadata GetMetadataWithOverrides(Type type)
{
if (type is null)

48
src/Avalonia.Base/AvaloniaProperty`1.cs

@ -1,4 +1,5 @@
using System;
using System.Reactive.Subjects;
using Avalonia.Data;
using Avalonia.Utilities;
@ -10,6 +11,8 @@ namespace Avalonia
/// <typeparam name="TValue">The value type of the property.</typeparam>
public abstract class AvaloniaProperty<TValue> : AvaloniaProperty
{
private readonly Subject<AvaloniaPropertyChangedEventArgs<TValue>> _changed;
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
/// </summary>
@ -24,22 +27,61 @@ namespace Avalonia
Action<IAvaloniaObject, bool> notifying = null)
: base(name, typeof(TValue), ownerType, metadata, notifying)
{
_changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();
}
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty"/> class.
/// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
[Obsolete("Use constructor with AvaloniaProperty<TValue> instead.", true)]
protected AvaloniaProperty(
AvaloniaProperty source,
Type ownerType,
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata)
: this(source as AvaloniaProperty<TValue> ?? throw new InvalidOperationException(), ownerType, metadata)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
protected AvaloniaProperty(
AvaloniaProperty<TValue> source,
Type ownerType,
PropertyMetadata metadata)
: base(source, ownerType, metadata)
{
_changed = source._changed;
}
/// <summary>
/// Gets an observable that is fired when this property changes on any
/// <see cref="AvaloniaObject"/> instance.
/// </summary>
/// <value>
/// An observable that is fired when this property changes on any
/// <see cref="AvaloniaObject"/> instance.
/// </value>
public new IObservable<AvaloniaPropertyChangedEventArgs<TValue>> Changed => _changed;
/// <summary>
/// Notifies the <see cref="Changed"/> observable.
/// </summary>
/// <param name="e">The observable arguments.</param>
internal void NotifyChanged(AvaloniaPropertyChangedEventArgs<TValue> e)
{
_changed.OnNext(e);
}
protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
protected BindingValue<object> TryConvert(object value)
{
if (value == UnsetValue)

17
src/Avalonia.Base/DirectPropertyBase.cs

@ -32,15 +32,30 @@ namespace Avalonia
}
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty"/> class.
/// Initializes a new instance of the <see cref="DirectPropertyBase{TValue}"/> class.
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
[Obsolete("Use constructor with DirectPropertyBase<TValue> instead.", true)]
protected DirectPropertyBase(
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata)
: this(source as DirectPropertyBase<TValue> ?? throw new InvalidOperationException(), ownerType, metadata)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DirectPropertyBase{TValue}"/> class.
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
protected DirectPropertyBase(
DirectPropertyBase<TValue> source,
Type ownerType,
PropertyMetadata metadata)
: base(source, ownerType, metadata)
{
}

2
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -24,12 +24,14 @@ using Avalonia.Input.Platform;
using System.ComponentModel.DataAnnotations;
using Avalonia.Controls.Utils;
using Avalonia.Layout;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
/// <summary>
/// Displays data in a customizable grid.
/// </summary>
[PseudoClasses(":invalid")]
public partial class DataGrid : TemplatedControl
{
private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter";

2
src/Avalonia.Controls.DataGrid/DataGridCell.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
@ -12,6 +13,7 @@ namespace Avalonia.Controls
/// <summary>
/// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> cell.
/// </summary>
[PseudoClasses(":selected", ":current", ":edited", ":invalid")]
public class DataGridCell : ContentControl
{
private const string DATAGRIDCELL_elementRightGridLine = "PART_RightGridLine";

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

@ -14,12 +14,14 @@ using Avalonia.Utilities;
using System;
using Avalonia.Controls.Utils;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
/// <summary>
/// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> column header.
/// </summary>
[PseudoClasses(":dragIndicator", ":pressed", ":sortascending", ":sortdescending")]
public class DataGridColumnHeader : ContentControl
{
private enum DragMode

2
src/Avalonia.Controls.DataGrid/DataGridRow.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
@ -20,6 +21,7 @@ namespace Avalonia.Controls
/// <summary>
/// Represents a <see cref="T:Avalonia.Controls.DataGrid" /> row.
/// </summary>
[PseudoClasses(":selected", ":editing", ":invalid")]
public class DataGridRow : TemplatedControl
{

2
src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
@ -13,6 +14,7 @@ using System.Reactive.Linq;
namespace Avalonia.Controls
{
[PseudoClasses(":pressed", ":current", ":expanded")]
public class DataGridRowGroupHeader : TemplatedControl
{
private const string DATAGRIDROWGROUPHEADER_expanderButton = "ExpanderButton";

2
src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Input;
using Avalonia.Media;
using System.Diagnostics;
@ -12,6 +13,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> row header.
/// </summary>
[PseudoClasses(":invalid", ":selected", ":editing", ":current")]
public class DataGridRowHeader : ContentControl
{
private const string DATAGRIDROWHEADER_elementRootName = "PART_Root";

96
src/Avalonia.Controls/AutoCompleteBox.cs

@ -14,6 +14,7 @@ using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Collections;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
@ -30,6 +31,7 @@ namespace Avalonia.Controls
/// <see cref="E:Avalonia.Controls.AutoCompleteBox.Populated" />
/// event.
/// </summary>
[PseudoClasses(":dropdownopen")]
public class PopulatedEventArgs : EventArgs
{
/// <summary>
@ -225,6 +227,27 @@ namespace Avalonia.Controls
Custom = 13,
}
/// <summary>
/// Represents the selector used by the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control to
/// determine how the specified text should be modified with an item.
/// </summary>
/// <returns>
/// Modified text that will be used by the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// </returns>
/// <param name="search">The string used as the basis for filtering.</param>
/// <param name="item">
/// The selected item that should be combined with the
/// <paramref name="search" /> parameter.
/// </param>
/// <typeparam name="T">
/// The type used for filtering the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// This type can be either a string or an object.
/// </typeparam>
public delegate string AutoCompleteSelector<T>(string search, T item);
/// <summary>
/// Represents a control that provides a text box for user input and a
/// drop-down that contains possible matches based on the input in the text
@ -362,6 +385,9 @@ namespace Avalonia.Controls
private AutoCompleteFilterPredicate<object> _itemFilter;
private AutoCompleteFilterPredicate<string> _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith);
private AutoCompleteSelector<object> _itemSelector;
private AutoCompleteSelector<string> _textSelector;
public static readonly RoutedEvent<SelectionChangedEventArgs> SelectionChangedEvent =
RoutedEvent.Register<SelectionChangedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox));
@ -528,6 +554,34 @@ namespace Avalonia.Controls
(o, v) => o.TextFilter = v,
unsetValue: AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith));
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemSelector" />
/// dependency property.
/// </summary>
/// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemSelector" />
/// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<object>> ItemSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<object>>(
nameof(ItemSelector),
o => o.ItemSelector,
(o, v) => o.ItemSelector = v);
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.
/// </summary>
/// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<string>> TextSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<string>>(
nameof(TextSelector),
o => o.TextSelector,
(o, v) => o.TextSelector = v);
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
@ -1061,6 +1115,40 @@ namespace Avalonia.Controls
set { SetAndRaise(TextFilterProperty, ref _textFilter, value); }
}
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </value>
public AutoCompleteSelector<object> ItemSelector
{
get { return _itemSelector; }
set { SetAndRaise(ItemSelectorProperty, ref _itemSelector, value); }
}
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
/// in a text-based way.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
/// in a text-based way.
/// </value>
public AutoCompleteSelector<string> TextSelector
{
get { return _textSelector; }
set { SetAndRaise(TextSelectorProperty, ref _textSelector, value); }
}
public Func<string, CancellationToken, Task<IEnumerable<object>>> AsyncPopulator
{
get { return _asyncPopulator; }
@ -2329,6 +2417,14 @@ namespace Avalonia.Controls
{
text = SearchText;
}
else if (TextSelector != null)
{
text = TextSelector(SearchText, FormatValue(newItem, true));
}
else if (ItemSelector != null)
{
text = ItemSelector(SearchText, newItem);
}
else
{
text = FormatValue(newItem, true);

2
src/Avalonia.Controls/Button.cs

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Windows.Input;
using Avalonia.Controls.Metadata;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -28,6 +29,7 @@ namespace Avalonia.Controls
/// <summary>
/// A button control.
/// </summary>
[PseudoClasses(":pressed")]
public class Button : ContentControl
{
/// <summary>

2
src/Avalonia.Controls/ButtonSpinner.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
@ -15,6 +16,7 @@ namespace Avalonia.Controls
/// <summary>
/// Represents a spinner control that includes two Buttons.
/// </summary>
[PseudoClasses(":left", ":right")]
public class ButtonSpinner : Spinner
{
/// <summary>

2
src/Avalonia.Controls/Calendar/CalendarButton.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Input;
using System;
@ -12,6 +13,7 @@ namespace Avalonia.Controls.Primitives
/// Represents a button on a
/// <see cref="T:Avalonia.Controls.Calendar" />.
/// </summary>
[PseudoClasses(":selected", ":inactive", ":btnfocused")]
public sealed class CalendarButton : Button
{
/// <summary>

2
src/Avalonia.Controls/Calendar/CalendarDayButton.cs

@ -5,10 +5,12 @@
using System;
using System.Globalization;
using Avalonia.Controls.Metadata;
using Avalonia.Input;
namespace Avalonia.Controls.Primitives
{
[PseudoClasses(":pressed", ":disabled", ":selected", ":inactive", ":today", ":blackout", ":dayfocused")]
public sealed class CalendarDayButton : Button
{
/// <summary>

2
src/Avalonia.Controls/Calendar/CalendarItem.cs

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Avalonia.Controls.Metadata;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -18,6 +19,7 @@ namespace Avalonia.Controls.Primitives
/// Represents the currently displayed month or year on a
/// <see cref="T:Avalonia.Controls.Calendar" />.
/// </summary>
[PseudoClasses(":calendardisabled")]
public sealed class CalendarItem : TemplatedControl
{
/// <summary>

2
src/Avalonia.Controls/Chrome/CaptionButtons.cs

@ -1,5 +1,6 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
#nullable enable
@ -9,6 +10,7 @@ namespace Avalonia.Controls.Chrome
/// <summary>
/// Draws window minimize / maximize / close buttons in a <see cref="TitleBar"/> when managed client decorations are enabled.
/// </summary>
[PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
public class CaptionButtons : TemplatedControl
{
private CompositeDisposable? _disposables;

2
src/Avalonia.Controls/Chrome/TitleBar.cs

@ -1,5 +1,6 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
#nullable enable
@ -9,6 +10,7 @@ namespace Avalonia.Controls.Chrome
/// <summary>
/// Draws a titlebar when managed client decorations are enabled.
/// </summary>
[PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
public class TitleBar : TemplatedControl
{
private CompositeDisposable? _disposables;

2
src/Avalonia.Controls/DataValidationErrors.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Templates;
using Avalonia.Data;
@ -14,6 +15,7 @@ namespace Avalonia.Controls
/// <remarks>
/// You will probably only want to create instances inside of control templates.
/// </remarks>
[PseudoClasses(":error")]
public class DataValidationErrors : ContentControl
{
/// <summary>

4
src/Avalonia.Controls/DateTimePickers/DatePicker.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Interactivity;
@ -11,6 +12,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control to allow the user to select a date
/// </summary>
[PseudoClasses(":hasnodate")]
public class DatePicker : TemplatedControl
{
/// <summary>

4
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using System;
@ -9,6 +10,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control to allow the user to select a time
/// </summary>
[PseudoClasses(":hasnotime")]
public class TimePicker : TemplatedControl
{
/// <summary>

3
src/Avalonia.Controls/Expander.cs

@ -1,6 +1,6 @@
using Avalonia.Animation;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
namespace Avalonia.Controls
{
@ -12,6 +12,7 @@ namespace Avalonia.Controls
Right
}
[PseudoClasses(":expanded", ":up", ":down", ":left", ":right")]
public class Expander : HeaderedContentControl
{
public static readonly StyledProperty<IPageTransition> ContentTransitionProperty =

9
src/Avalonia.Controls/IconElement.cs

@ -0,0 +1,9 @@
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
{
public abstract class IconElement : TemplatedControl
{
}
}

2
src/Avalonia.Controls/ItemsControl.cs

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
@ -18,6 +19,7 @@ namespace Avalonia.Controls
/// <summary>
/// Displays a collection of items.
/// </summary>
[PseudoClasses(":empty", ":singleitem")]
public class ItemsControl : TemplatedControl, IItemsPresenterHost, ICollectionChangedListener
{
/// <summary>

2
src/Avalonia.Controls/ListBoxItem.cs

@ -1,3 +1,4 @@
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Input;
@ -6,6 +7,7 @@ namespace Avalonia.Controls
/// <summary>
/// A selectable item in a <see cref="ListBox"/>.
/// </summary>
[PseudoClasses(":pressed", ":selected")]
public class ListBoxItem : ContentControl, ISelectable
{
/// <summary>

2
src/Avalonia.Controls/MenuItem.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
@ -20,6 +21,7 @@ namespace Avalonia.Controls
/// <summary>
/// A menu item control.
/// </summary>
[PseudoClasses(":separator", ":icon", ":open", ":pressed", ":selected")]
public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable
{
/// <summary>

4
src/Avalonia.Controls/Mixins/SelectableMixin.cs

@ -48,7 +48,7 @@ namespace Avalonia.Controls.Mixins
if (sender != null)
{
((IPseudoClasses)sender.Classes).Set(":selected", (bool)x.NewValue);
((IPseudoClasses)sender.Classes).Set(":selected", x.NewValue.GetValueOrDefault());
sender.RaiseEvent(new RoutedEventArgs
{
@ -58,4 +58,4 @@ namespace Avalonia.Controls.Mixins
});
}
}
}
}

2
src/Avalonia.Controls/NativeMenu.Export.cs

@ -77,7 +77,7 @@ namespace Avalonia.Controls
{
if (args.Sender is TopLevel tl)
{
GetInfo(tl).Exporter?.SetNativeMenu((NativeMenu)args.NewValue);
GetInfo(tl).Exporter?.SetNativeMenu(args.NewValue.GetValueOrDefault());
}
});
}

2
src/Avalonia.Controls/NativeMenuItem.cs

@ -23,7 +23,7 @@ namespace Avalonia.Controls
MenuProperty.Changed.Subscribe(args =>
{
var item = (NativeMenuItem)args.Sender;
var value = (NativeMenu)args.NewValue;
var value = args.NewValue.GetValueOrDefault();
if (value.Parent != null && value.Parent != item)
throw new InvalidOperationException("NativeMenu already has a parent");
value.Parent = item;

2
src/Avalonia.Controls/Notifications/NotificationCard.cs

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
@ -9,6 +10,7 @@ namespace Avalonia.Controls.Notifications
/// <summary>
/// Control that represents and displays a notification.
/// </summary>
[PseudoClasses(":error", ":information", ":success", ":warning")]
public class NotificationCard : ContentControl
{
private bool _isClosed;

2
src/Avalonia.Controls/Notifications/WindowNotificationManager.cs

@ -7,12 +7,14 @@ using Avalonia.Controls.Primitives;
using Avalonia.Rendering;
using Avalonia.Data;
using Avalonia.VisualTree;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls.Notifications
{
/// <summary>
/// An <see cref="INotificationManager"/> that displays notifications in a <see cref="Window"/>.
/// </summary>
[PseudoClasses(":topleft", ":topright", ":bottomleft", ":bottomright")]
public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager, ICustomSimpleHitTest
{
private IList _items;

21
src/Avalonia.Controls/PathIcon.cs

@ -0,0 +1,21 @@
using Avalonia.Media;
namespace Avalonia.Controls
{
public class PathIcon : IconElement
{
static PathIcon()
{
AffectsRender<PathIcon>(DataProperty);
}
public static readonly StyledProperty<Geometry> DataProperty =
AvaloniaProperty.Register<PathIcon, Geometry>(nameof(Data));
public Geometry Data
{
get { return GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
}
}

2
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -82,7 +82,7 @@ namespace Avalonia.Controls.Presenters
TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty,
TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty);
Observable.Merge(TextProperty.Changed, TextBlock.ForegroundProperty.Changed,
Observable.Merge<AvaloniaPropertyChangedEventArgs>(TextProperty.Changed, TextBlock.ForegroundProperty.Changed,
TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed,
TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed,

4
src/Avalonia.Controls/Primitives/AccessText.cs

@ -126,7 +126,7 @@ namespace Avalonia.Controls.Primitives
if (shapedTextCharacters.GlyphRun.Characters.End < textPosition)
{
currentX += shapedTextCharacters.GlyphRun.Bounds.Width;
currentX += shapedTextCharacters.Size.Width;
continue;
}
@ -143,7 +143,7 @@ namespace Avalonia.Controls.Primitives
width = 0.0;
}
return new Rect(currentX, currentY, width, shapedTextCharacters.GlyphRun.Bounds.Height);
return new Rect(currentX, currentY, width, shapedTextCharacters.Size.Height);
}
}

3
src/Avalonia.Controls/Primitives/IPopupHost.cs

@ -1,6 +1,7 @@
using System;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
@ -13,7 +14,7 @@ namespace Avalonia.Controls.Primitives
/// (<see cref="PopupRoot"/>) or an <see cref="OverlayPopupHost"/> which is created
/// on an <see cref="OverlayLayer"/>.
/// </remarks>
public interface IPopupHost : IDisposable
public interface IPopupHost : IDisposable, IFocusScope
{
/// <summary>
/// Sets the control to display in the popup.

2
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs

@ -221,7 +221,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Bottom))
{
unconstrainedRect = unconstrainedRect.WithHeight(bounds.Height - unconstrainedRect.Y);
unconstrainedRect = unconstrainedRect.WithHeight(bounds.Bottom - unconstrainedRect.Y);
}
if (IsValid(unconstrainedRect))

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

@ -4,6 +4,7 @@ using Avalonia.Interactivity;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Threading;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls.Primitives
{
@ -21,6 +22,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// A scrollbar control.
/// </summary>
[PseudoClasses(":vertical", ":horizontal")]
public class ScrollBar : RangeBase
{
/// <summary>

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

@ -1,9 +1,11 @@
using System;
using Avalonia.Controls.Metadata;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Primitives
{
[PseudoClasses(":pressed")]
public class Thumb : TemplatedControl
{
public static readonly RoutedEvent<VectorEventArgs> DragStartedEvent =

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

@ -1,4 +1,5 @@
using System;
using Avalonia.Controls.Metadata;
using Avalonia.Data;
using Avalonia.Interactivity;
@ -7,6 +8,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Represents a control that a user can select (check) or clear (uncheck). Base class for controls that can switch states.
/// </summary>
[PseudoClasses(":checked", ":unchecked", ":indeterminate")]
public class ToggleButton : Button
{
/// <summary>

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

@ -4,6 +4,7 @@
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using Avalonia.Controls.Metadata;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Layout;
@ -12,6 +13,7 @@ using Avalonia.Utilities;
namespace Avalonia.Controls.Primitives
{
[PseudoClasses(":vertical", ":horizontal")]
public class Track : Control
{
public static readonly DirectProperty<Track, double> MinimumProperty =

2
src/Avalonia.Controls/ProgressBar.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.Media;
@ -8,6 +9,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control used to indicate the progress of an operation.
/// </summary>
[PseudoClasses(":vertical", ":horizontal", ":indeterminate")]
public class ProgressBar : RangeBase
{
public class ProgressBarTemplateProperties : AvaloniaObject

2
src/Avalonia.Controls/Slider.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Collections;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
@ -39,6 +40,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control that lets the user select from a range of values by moving a Thumb control along a Track.
/// </summary>
[PseudoClasses(":vertical", ":horizontal", ":pressed")]
public class Slider : RangeBase
{
/// <summary>

7
src/Avalonia.Controls/SplitView.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Interactivity;
@ -73,6 +74,10 @@ namespace Avalonia.Controls
/// <summary>
/// A control with two views: A collapsible pane and an area for content
/// </summary>
[PseudoClasses(":open", ":closed")]
[PseudoClasses(":compactoverlay", ":compactinline", ":overlay", ":inline")]
[PseudoClasses(":left", ":right")]
[PseudoClasses(":lightdismiss")]
public class SplitView : TemplatedControl
{
/*

2
src/Avalonia.Controls/TabItem.cs

@ -1,3 +1,4 @@
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
@ -6,6 +7,7 @@ namespace Avalonia.Controls
/// <summary>
/// An item in a <see cref="TabStrip"/> or <see cref="TabControl"/>.
/// </summary>
[PseudoClasses(":pressed", ":selected")]
public class TabItem : HeaderedContentControl, ISelectable
{
/// <summary>

7
src/Avalonia.Controls/TextBlock.cs

@ -138,7 +138,7 @@ namespace Avalonia.Controls
FontStyleProperty, TextWrappingProperty, FontFamilyProperty,
TextTrimmingProperty, TextProperty, PaddingProperty, LineHeightProperty, MaxLinesProperty);
Observable.Merge(TextProperty.Changed, ForegroundProperty.Changed,
Observable.Merge<AvaloniaPropertyChangedEventArgs>(TextProperty.Changed, ForegroundProperty.Changed,
TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
TextTrimmingProperty.Changed, FontSizeProperty.Changed,
FontStyleProperty.Changed, FontWeightProperty.Changed,
@ -434,7 +434,10 @@ namespace Avalonia.Controls
var padding = Padding;
TextLayout.Draw(context, new Point(padding.Left + offsetX, padding.Top));
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top)))
{
TextLayout.Draw(context);
}
}
/// <summary>

2
src/Avalonia.Controls/TextBox.cs

@ -13,9 +13,11 @@ using Avalonia.Metadata;
using Avalonia.Data;
using Avalonia.Layout;
using Avalonia.Utilities;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
[PseudoClasses(":empty")]
public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.IUndoRedoHost
{
public static KeyGesture CutGesture { get; } = AvaloniaLocator.Current

4
src/Avalonia.Controls/ToggleSwitch.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.LogicalTree;
@ -8,6 +9,7 @@ namespace Avalonia.Controls
/// <summary>
/// A Toggle Switch control.
/// </summary>
[PseudoClasses(":dragging")]
public class ToggleSwitch : ToggleButton
{
private Panel _knobsPanel;

2
src/Avalonia.Controls/ToolTip.cs

@ -1,5 +1,6 @@
using System;
using System.Reactive.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.VisualTree;
@ -14,6 +15,7 @@ namespace Avalonia.Controls
/// To add a tooltip to a control, use the <see cref="TipProperty"/> attached property,
/// assigning the content that you want displayed.
/// </remarks>
[PseudoClasses(":open")]
public class ToolTip : ContentControl
{
/// <summary>

2
src/Avalonia.Controls/TreeViewItem.cs

@ -1,5 +1,6 @@
using System.Linq;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
@ -11,6 +12,7 @@ namespace Avalonia.Controls
/// <summary>
/// An item in a <see cref="TreeView"/>.
/// </summary>
[PseudoClasses(":pressed", ":selected")]
public class TreeViewItem : HeaderedItemsControl, ISelectable
{
/// <summary>

2
src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -385,7 +385,7 @@ namespace Avalonia.Headless
}
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
}

2
src/Avalonia.Input/InputElement.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Data;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity;
@ -12,6 +13,7 @@ namespace Avalonia.Input
/// <summary>
/// Implements input-related functionality for a control.
/// </summary>
[PseudoClasses(":disabled", ":focus", ":focus-visible", ":pointerover")]
public class InputElement : Interactive, IInputElement
{
/// <summary>

8
src/Avalonia.Native/Avalonia.Native.csproj

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsPackable>false</IsPackable>
<PackAvaloniaNative Condition="'$(PackAvaloniaNative)' == ''">$([MSBuild]::IsOSPlatform(OSX))</PackAvaloniaNative>
<IsPackable>$(PackAvaloniaNative)</IsPackable>
<IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable>
<TargetFramework>netstandard2.0</TargetFramework>
<CastXmlPath Condition="Exists('/usr/bin/castxml')">/usr/bin/castxml</CastXmlPath>
@ -10,8 +11,9 @@
<SharpGenGenerateConsumerBindMapping>false</SharpGenGenerateConsumerBindMapping>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release' AND '$([MSBuild]::IsOSPlatform(OSX))' == 'true'">
<ItemGroup Condition="'$(PackAvaloniaNative)' == 'true'">
<Content Include="../../Build/Products/Release/libAvalonia.Native.OSX.dylib">
<Link>libAvaloniaNative.dylib</Link>
<PackagePath>runtimes/osx/native/libAvaloniaNative.dylib</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@ -26,4 +28,4 @@
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
</ItemGroup>
</Project>
</Project>

8
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -16,7 +16,7 @@ namespace Avalonia.Native
{
private readonly IAvaloniaNativeFactory _factory;
private AvaloniaNativePlatformOptions _options;
private GlPlatformFeature _glFeature;
private AvaloniaNativePlatformOpenGlInterface _platformGl;
[DllImport("libAvaloniaNative")]
static extern IntPtr CreateAvaloniaNative();
@ -116,8 +116,8 @@ namespace Avalonia.Native
{
try
{
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>()
.ToConstant(_glFeature = new GlPlatformFeature(_factory.ObtainGlDisplay()));
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>()
.ToConstant(_platformGl = new AvaloniaNativePlatformOpenGlInterface(_factory.ObtainGlDisplay()));
}
catch (Exception)
{
@ -128,7 +128,7 @@ namespace Avalonia.Native
public IWindowImpl CreateWindow()
{
return new WindowImpl(_factory, _options, _glFeature);
return new WindowImpl(_factory, _options, _platformGl);
}
public IWindowImpl CreateEmbeddableWindow()

41
src/Avalonia.Native/GlPlatformFeature.cs → src/Avalonia.Native/AvaloniaNativePlatformOpenGlInterface.cs

@ -2,21 +2,20 @@
using Avalonia.OpenGL;
using Avalonia.Native.Interop;
using System.Drawing;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Threading;
namespace Avalonia.Native
{
class GlPlatformFeature : IWindowingPlatformGlFeature
class AvaloniaNativePlatformOpenGlInterface : IPlatformOpenGlInterface
{
private readonly IAvnGlDisplay _display;
public GlPlatformFeature(IAvnGlDisplay display)
public AvaloniaNativePlatformOpenGlInterface(IAvnGlDisplay display)
{
_display = display;
var immediate = display.CreateContext(null);
var deferred = display.CreateContext(immediate);
int major, minor;
GlInterface glInterface;
using (immediate.MakeCurrent())
@ -33,19 +32,22 @@ namespace Avalonia.Native
}
GlDisplay = new GlDisplay(display, glInterface, immediate.SampleCount, immediate.StencilSize);
ImmediateContext = new GlContext(GlDisplay, immediate, _version);
DeferredContext = new GlContext(GlDisplay, deferred, _version);
MainContext = new GlContext(GlDisplay, null, immediate, _version);
}
internal IGlContext ImmediateContext { get; }
public IGlContext MainContext => DeferredContext;
internal GlContext DeferredContext { get; }
internal GlContext MainContext { get; }
public IGlContext PrimaryContext => MainContext;
public bool CanShareContexts => true;
public bool CanCreateContexts => true;
internal GlDisplay GlDisplay;
private readonly GlVersion _version;
public IGlContext CreateSharedContext() => new GlContext(GlDisplay,
MainContext, _display.CreateContext(MainContext.Context), _version);
public IGlContext CreateContext() => new GlContext(GlDisplay,
_display.CreateContext(((GlContext)ImmediateContext).Context), _version);
null, _display.CreateContext(null), _version);
}
class GlDisplay
@ -72,11 +74,13 @@ namespace Avalonia.Native
class GlContext : IGlContext
{
private readonly GlDisplay _display;
private readonly GlContext _sharedWith;
public IAvnGlContext Context { get; private set; }
public GlContext(GlDisplay display, IAvnGlContext context, GlVersion version)
public GlContext(GlDisplay display, GlContext sharedWith, IAvnGlContext context, GlVersion version)
{
_display = display;
_sharedWith = sharedWith;
Context = context;
Version = version;
}
@ -86,6 +90,17 @@ namespace Avalonia.Native
public int SampleCount => _display.SampleCount;
public int StencilSize => _display.StencilSize;
public IDisposable MakeCurrent() => Context.MakeCurrent();
public IDisposable EnsureCurrent() => MakeCurrent();
public bool IsSharedWith(IGlContext context)
{
var c = (GlContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
public void Dispose()
{
@ -108,7 +123,7 @@ namespace Avalonia.Native
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var feature = (GlPlatformFeature)AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
var feature = (AvaloniaNativePlatformOpenGlInterface)AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
return new GlPlatformSurfaceRenderingSession(_context, _target.BeginDrawing());
}

6
src/Avalonia.Native/PopupImpl.cs

@ -9,12 +9,12 @@ namespace Avalonia.Native
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
private readonly GlPlatformFeature _glFeature;
private readonly AvaloniaNativePlatformOpenGlInterface _glFeature;
private readonly IWindowBaseImpl _parent;
public PopupImpl(IAvaloniaNativeFactory factory,
AvaloniaNativePlatformOptions opts,
GlPlatformFeature glFeature,
AvaloniaNativePlatformOpenGlInterface glFeature,
IWindowBaseImpl parent) : base(opts, glFeature)
{
_factory = factory;
@ -23,7 +23,7 @@ namespace Avalonia.Native
_parent = parent;
using (var e = new PopupEvents(this))
{
var context = _opts.UseGpu ? glFeature?.DeferredContext : null;
var context = _opts.UseGpu ? glFeature?.MainContext : null;
Init(factory.CreatePopup(e, context?.Context), factory.CreateScreens(), context);
}
PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(parent, MoveResize));

6
src/Avalonia.Native/WindowImpl.cs

@ -14,19 +14,19 @@ namespace Avalonia.Native
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
private readonly GlPlatformFeature _glFeature;
private readonly AvaloniaNativePlatformOpenGlInterface _glFeature;
IAvnWindow _native;
private double _extendTitleBarHeight = -1;
internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
GlPlatformFeature glFeature) : base(opts, glFeature)
AvaloniaNativePlatformOpenGlInterface glFeature) : base(opts, glFeature)
{
_factory = factory;
_opts = opts;
_glFeature = glFeature;
using (var e = new WindowEvents(this))
{
var context = _opts.UseGpu ? glFeature?.DeferredContext : null;
var context = _opts.UseGpu ? glFeature?.MainContext : null;
Init(_native = factory.CreateWindow(e, context?.Context), factory.CreateScreens(), context);
}

2
src/Avalonia.Native/WindowImplBase.cs

@ -61,7 +61,7 @@ namespace Avalonia.Native
private NativeControlHostImpl _nativeControlHost;
private IGlContext _glContext;
internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, GlPlatformFeature glFeature)
internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, AvaloniaNativePlatformOpenGlInterface glFeature)
{
_gpu = opts.UseGpu && glFeature != null;
_deferredRendering = opts.UseDeferredRendering;

1
src/Avalonia.OpenGL/Angle/AngleEglInterface.cs

@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Platform.Interop;

10
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using static Avalonia.OpenGL.EglConsts;
using Avalonia.OpenGL.Egl;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL.Angle
{
@ -52,7 +52,7 @@ namespace Avalonia.OpenGL.Angle
}
}
private AngleWin32EglDisplay(EglInterface egl, AngleInfo info) : base(egl, info.Display)
private AngleWin32EglDisplay(EglInterface egl, AngleInfo info) : base(egl, false, info.Display)
{
PlatformApi = info.PlatformApi;
}
@ -78,11 +78,11 @@ namespace Avalonia.OpenGL.Angle
return d3dDeviceHandle;
}
public EglSurface WrapDirect3D11Texture(IntPtr handle)
public EglSurface WrapDirect3D11Texture(EglPlatformOpenGlInterface egl, IntPtr handle)
{
if (PlatformApi != AngleOptions.PlatformApi.DirectX11)
throw new InvalidOperationException("Current platform API is " + PlatformApi);
return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
}
}
}

192
src/Avalonia.OpenGL/OpenGlControlBase.cs → src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

@ -3,44 +3,83 @@ using Avalonia.Controls;
using Avalonia.Logging;
using Avalonia.Media;
using Avalonia.OpenGL.Imaging;
using Avalonia.Rendering;
using Avalonia.VisualTree;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Controls
{
public abstract class OpenGlControlBase : Control
{
private IGlContext _context;
private int _fb, _texture, _renderBuffer;
private OpenGlTextureBitmap _bitmap;
private PixelSize _oldSize;
private int _fb, _depthBuffer;
private OpenGlBitmap _bitmap;
private IOpenGlBitmapAttachment _attachment;
private PixelSize _depthBufferSize;
private bool _glFailed;
private bool _initialized;
protected GlVersion GlVersion { get; private set; }
public sealed override void Render(DrawingContext context)
{
if(!EnsureInitialized())
return;
using (_context.MakeCurrent())
{
using (_bitmap.Lock())
{
var gl = _context.GlInterface;
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
if (_oldSize != GetPixelSize())
ResizeTexture(gl);
OnOpenGlRender(gl, _fb);
gl.Flush();
}
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, _fb);
EnsureTextureAttachment();
EnsureDepthBufferAttachment(_context.GlInterface);
if(!CheckFramebufferStatus(_context.GlInterface))
return;
OnOpenGlRender(_context.GlInterface, _fb);
_attachment.Present();
}
context.DrawImage(_bitmap, new Rect(_bitmap.Size), Bounds);
base.Render(context);
}
private void CheckError(GlInterface gl)
{
int err;
while ((err = gl.GetError()) != GL_NO_ERROR)
Console.WriteLine(err);
}
void EnsureTextureAttachment()
{
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, _fb);
if (_bitmap == null || _attachment == null || _bitmap.PixelSize != GetPixelSize())
{
_attachment?.Dispose();
_attachment = null;
_bitmap?.Dispose();
_bitmap = null;
_bitmap = new OpenGlBitmap(GetPixelSize(), new Vector(96, 96));
_attachment = _bitmap.CreateFramebufferAttachment(_context);
}
}
void EnsureDepthBufferAttachment(GlInterface gl)
{
var size = GetPixelSize();
if (size == _depthBufferSize && _depthBuffer != 0)
return;
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer);
if (_depthBuffer != 0) gl.DeleteRenderbuffers(1, new[] { _depthBuffer });
var oneArr = new int[1];
gl.GenRenderbuffers(1, oneArr);
_depthBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
size.Width, size.Height);
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
}
void DoCleanup(bool callUserDeinit)
void DoCleanup()
{
if (_context != null)
{
@ -50,16 +89,19 @@ namespace Avalonia.OpenGL
gl.BindTexture(GL_TEXTURE_2D, 0);
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
gl.DeleteFramebuffers(1, new[] { _fb });
using (_bitmap.Lock())
_bitmap.SetTexture(0, 0, new PixelSize(1, 1), 1);
gl.DeleteTextures(1, new[] { _texture });
gl.DeleteRenderbuffers(1, new[] { _renderBuffer });
_bitmap.Dispose();
gl.DeleteRenderbuffers(1, new[] { _depthBuffer });
_attachment?.Dispose();
_attachment = null;
_bitmap?.Dispose();
_bitmap = null;
try
{
if (callUserDeinit)
if (_initialized)
{
_initialized = false;
OnOpenGlDeinit(_context.GlInterface, _fb);
}
}
finally
{
@ -72,11 +114,11 @@ namespace Avalonia.OpenGL
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
DoCleanup(true);
DoCleanup();
base.OnDetachedFromVisualTree(e);
}
bool EnsureInitialized()
private bool EnsureInitializedCore()
{
if (_context != null)
return true;
@ -84,34 +126,43 @@ namespace Avalonia.OpenGL
if (_glFailed)
return false;
var feature = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
var feature = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
if (feature == null)
return false;
if (!feature.CanShareContexts)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: current platform does not support multithreaded context sharing");
return false;
}
try
{
_context = feature.CreateContext();
_context = feature.CreateSharedContext();
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: unable to create additional OpenGL context: {exception}", e);
_glFailed = true;
return false;
}
GlVersion = _context.Version;
try
{
_bitmap = new OpenGlTextureBitmap();
_bitmap = new OpenGlBitmap(GetPixelSize(), new Vector(96, 96));
if (!_bitmap.SupportsContext(_context))
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: unable to create OpenGlBitmap: OpenGL context is not compatible");
return false;
}
}
catch (Exception e)
{
_context.Dispose();
_context = null;
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: unable to create OpenGlTextureBitmap: {exception}", e);
_glFailed = true;
"Unable to initialize OpenGL: unable to create OpenGlBitmap: {exception}", e);
return false;
}
@ -119,80 +170,55 @@ namespace Avalonia.OpenGL
{
try
{
_oldSize = GetPixelSize();
_depthBufferSize = GetPixelSize();
var gl = _context.GlInterface;
var oneArr = new int[1];
gl.GenFramebuffers(1, oneArr);
_fb = oneArr[0];
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
gl.GenTextures(1, oneArr);
_texture = oneArr[0];
ResizeTexture(gl);
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
EnsureDepthBufferAttachment(gl);
EnsureTextureAttachment();
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
int code;
while ((code = gl.GetError()) != 0)
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL FBO: {code}", code);
_glFailed = true;
return false;
}
return CheckFramebufferStatus(gl);
}
catch(Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL FBO: {exception}", e);
_glFailed = true;
return false;
}
if (!_glFailed)
OnOpenGlInit(_context.GlInterface, _fb);
}
}
if (_glFailed)
private bool CheckFramebufferStatus(GlInterface gl)
{
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
DoCleanup(false);
int code;
while ((code = gl.GetError()) != 0)
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL FBO: {code}", code);
return false;
}
return true;
}
void ResizeTexture(GlInterface gl)
private bool EnsureInitialized()
{
var size = GetPixelSize();
gl.GetIntegerv( GL_TEXTURE_BINDING_2D, out var oldTexture);
gl.BindTexture(GL_TEXTURE_2D, _texture);
gl.TexImage2D(GL_TEXTURE_2D, 0,
GlVersion.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8,
size.Width, size.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.BindTexture(GL_TEXTURE_2D, oldTexture);
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer);
gl.DeleteRenderbuffers(1, new[] { _renderBuffer });
var oneArr = new int[1];
gl.GenRenderbuffers(1, oneArr);
_renderBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
size.Width, size.Height);
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer);
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
using (_bitmap.Lock())
_bitmap.SetTexture(_texture, GL_RGBA8, size, 1);
if (_initialized)
return true;
_glFailed = !(_initialized = EnsureInitializedCore());
if (_glFailed)
return false;
using (_context.MakeCurrent())
OnOpenGlInit(_context.GlInterface, _fb);
return true;
}
PixelSize GetPixelSize()
private PixelSize GetPixelSize()
{
var scaling = VisualRoot.RenderScaling;
return new PixelSize(Math.Max(1, (int)(Bounds.Width * scaling)),

2
src/Avalonia.OpenGL/EglConsts.cs → src/Avalonia.OpenGL/Egl/EglConsts.cs

@ -1,6 +1,6 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable IdentifierTypo
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public static class EglConsts
{

69
src/Avalonia.OpenGL/EglContext.cs → src/Avalonia.OpenGL/Egl/EglContext.cs

@ -1,23 +1,25 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
using static Avalonia.OpenGL.EglConsts;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglContext : IGlContext
{
private readonly EglDisplay _disp;
private readonly EglInterface _egl;
private readonly EglContext _sharedWith;
private readonly object _lock = new object();
public EglContext(EglDisplay display, EglInterface egl, IntPtr ctx, EglSurface offscreenSurface,
public EglContext(EglDisplay display, EglInterface egl, EglContext sharedWith, IntPtr ctx, Func<EglContext, EglSurface> offscreenSurface,
GlVersion version, int sampleCount, int stencilSize)
{
_disp = display;
_egl = egl;
_sharedWith = sharedWith;
Context = ctx;
OffscreenSurface = offscreenSurface;
OffscreenSurface = offscreenSurface(this);
Version = version;
SampleCount = sampleCount;
StencilSize = stencilSize;
@ -33,21 +35,17 @@ namespace Avalonia.OpenGL
public int StencilSize { get; }
public EglDisplay Display => _disp;
public IDisposable Lock()
{
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
class RestoreContext : IDisposable
{
private readonly EglInterface _egl;
private readonly object _l;
private readonly IntPtr _display;
private IntPtr _context, _read, _draw;
public RestoreContext(EglInterface egl, IntPtr defDisplay)
public RestoreContext(EglInterface egl, IntPtr defDisplay, object l)
{
_egl = egl;
_l = l;
_display = _egl.GetCurrentDisplay();
if (_display == IntPtr.Zero)
_display = defDisplay;
@ -59,29 +57,52 @@ namespace Avalonia.OpenGL
public void Dispose()
{
_egl.MakeCurrent(_display, _draw, _read, _context);
Monitor.Exit(_l);
}
}
public IDisposable MakeCurrent()
public IDisposable MakeCurrent() => MakeCurrent(OffscreenSurface);
public IDisposable MakeCurrent(EglSurface surface)
{
var old = new RestoreContext(_egl, _disp.Handle);
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, Context))
throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
return old;
Monitor.Enter(_lock);
var success = false;
try
{
var old = new RestoreContext(_egl, _disp.Handle, _lock);
var surf = surface ?? OffscreenSurface;
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, surf.DangerousGetHandle(), surf.DangerousGetHandle(), Context))
throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
success = true;
return old;
}
finally
{
if(!success)
Monitor.Enter(_lock);
}
}
public IDisposable MakeCurrent(EglSurface surface)
public IDisposable EnsureCurrent()
{
var old = new RestoreContext(_egl, _disp.Handle);
var surf = surface ?? OffscreenSurface;
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, surf.DangerousGetHandle(), surf.DangerousGetHandle(), Context))
throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
return old;
if(IsCurrent)
return Disposable.Empty;
return MakeCurrent();
}
public bool IsSharedWith(IGlContext context)
{
var c = (EglContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
public bool IsCurrent => _egl.GetCurrentDisplay() == _disp.Handle && _egl.GetCurrentContext() == Context;
public void Dispose()
{
_egl.DestroyContext(_disp.Handle, Context);

53
src/Avalonia.OpenGL/EglDisplay.cs → src/Avalonia.OpenGL/Egl/EglDisplay.cs

@ -1,26 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.EglConsts;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglDisplay
{
private readonly EglInterface _egl;
public bool SupportsSharing { get; }
private readonly IntPtr _display;
private readonly IntPtr _config;
private readonly int[] _contextAttributes;
private readonly int _surfaceType;
public IntPtr Handle => _display;
public IntPtr Config => _config;
private int _sampleCount;
private int _stencilSize;
private GlVersion _version;
public EglDisplay(EglInterface egl) : this(egl, -1, IntPtr.Zero, null)
public EglDisplay(EglInterface egl, bool supportsSharing) : this(egl, supportsSharing, -1, IntPtr.Zero, null)
{
}
@ -45,15 +44,16 @@ namespace Avalonia.OpenGL
return display;
}
public EglDisplay(EglInterface egl, int platformType, IntPtr platformDisplay, int[] attrs)
: this(egl, CreateDisplay(egl, platformType, platformDisplay, attrs))
public EglDisplay(EglInterface egl, bool supportsSharing, int platformType, IntPtr platformDisplay, int[] attrs)
: this(egl, supportsSharing, CreateDisplay(egl, platformType, platformDisplay, attrs))
{
}
public EglDisplay(EglInterface egl, IntPtr display)
public EglDisplay(EglInterface egl, bool supportsSharing, IntPtr display)
{
_egl = egl;
SupportsSharing = supportsSharing;
_display = display;
if(_display == IntPtr.Zero)
throw new ArgumentException();
@ -136,7 +136,12 @@ namespace Avalonia.OpenGL
throw new OpenGlException("No suitable EGL config was found");
}
public EglDisplay() : this(new EglInterface())
public EglDisplay() : this(false)
{
}
public EglDisplay(bool supportsSharing) : this(new EglInterface(), supportsSharing)
{
}
@ -144,6 +149,9 @@ namespace Avalonia.OpenGL
public EglInterface EglInterface => _egl;
public EglContext CreateContext(IGlContext share)
{
if (share != null && !SupportsSharing)
throw new NotSupportedException("Context sharing is not supported by this display");
if((_surfaceType|EGL_PBUFFER_BIT) == 0)
throw new InvalidOperationException("Platform doesn't support PBUFFER surfaces");
var shareCtx = (EglContext)share;
@ -158,37 +166,22 @@ namespace Avalonia.OpenGL
});
if (surf == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePBufferSurface", _egl);
var rv = new EglContext(this, _egl, ctx, new EglSurface(this, _egl, surf),
var rv = new EglContext(this, _egl, shareCtx, ctx, context => new EglSurface(this, context, surf),
_version, _sampleCount, _stencilSize);
return rv;
}
public EglContext CreateContext(EglContext share, EglSurface offscreenSurface)
{
if (share != null && !SupportsSharing)
throw new NotSupportedException("Context sharing is not supported by this display");
var ctx = _egl.CreateContext(_display, _config, share?.Context ?? IntPtr.Zero, _contextAttributes);
if (ctx == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateContext", _egl);
var rv = new EglContext(this, _egl, ctx, offscreenSurface, _version, _sampleCount, _stencilSize);
var rv = new EglContext(this, _egl, share, ctx, _ => offscreenSurface, _version, _sampleCount, _stencilSize);
rv.MakeCurrent(null);
return rv;
}
public EglSurface CreateWindowSurface(IntPtr window)
{
var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", _egl);
return new EglSurface(this, _egl, s);
}
public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs)
{
var s = _egl.CreatePbufferFromClientBuffer(_display, bufferType, handle,
_config, attribs);
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePbufferFromClientBuffer", _egl);
return new EglSurface(this, _egl, s);
}
}
}

2
src/Avalonia.OpenGL/EglErrors.cs → src/Avalonia.OpenGL/Egl/EglErrors.cs

@ -1,4 +1,4 @@
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public enum EglErrors
{

54
src/Avalonia.OpenGL/Egl/EglGlPlatformSurface.cs

@ -0,0 +1,54 @@
using Avalonia.OpenGL.Surfaces;
namespace Avalonia.OpenGL.Egl
{
public class EglGlPlatformSurface : EglGlPlatformSurfaceBase
{
private readonly EglPlatformOpenGlInterface _egl;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) : base()
{
_egl = egl;
_info = info;
}
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
var glSurface = _egl.CreateWindowSurface(_info.Handle);
return new RenderTarget(_egl, glSurface, _info);
}
class RenderTarget : EglPlatformSurfaceRenderTargetBase
{
private readonly EglPlatformOpenGlInterface _egl;
private EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _currentSize;
public RenderTarget(EglPlatformOpenGlInterface egl,
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) : base(egl)
{
_egl = egl;
_glSurface = glSurface;
_info = info;
_currentSize = info.Size;
}
public override void Dispose() => _glSurface.Dispose();
public override IGlPlatformSurfaceRenderingSession BeginDraw()
{
if (_info.Size != _currentSize || _glSurface == null)
{
_glSurface?.Dispose();
_glSurface = null;
_glSurface = _egl.CreateWindowSurface(_info.Handle);
_currentSize = _info.Size;
}
return base.BeginDraw(_glSurface, _info);
}
}
}
}

47
src/Avalonia.OpenGL/EglGlPlatformSurfaceBase.cs → src/Avalonia.OpenGL/Egl/EglGlPlatformSurfaceBase.cs

@ -1,6 +1,7 @@
using System;
using Avalonia.OpenGL.Surfaces;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public abstract class EglGlPlatformSurfaceBase : IGlPlatformSurface
{
@ -14,19 +15,15 @@ namespace Avalonia.OpenGL
public abstract IGlPlatformSurfaceRenderTarget CreateGlRenderTarget();
}
public abstract class EglPlatformSurfaceRenderTargetBase : IGlPlatformSurfaceRenderTargetWithCorruptionInfo
public abstract class EglPlatformSurfaceRenderTargetBase : IGlPlatformSurfaceRenderTarget
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglPlatformOpenGlInterface _egl;
protected EglPlatformSurfaceRenderTargetBase(EglDisplay display, EglContext context)
protected EglPlatformSurfaceRenderTargetBase(EglPlatformOpenGlInterface egl)
{
_display = display;
_context = context;
_egl = egl;
}
public abstract bool IsCorrupted { get; }
public virtual void Dispose()
{
@ -37,22 +34,25 @@ namespace Avalonia.OpenGL
protected IGlPlatformSurfaceRenderingSession BeginDraw(EglSurface surface,
EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info, Action onFinish = null, bool isYFlipped = false)
{
var l = _context.Lock();
var restoreContext = _egl.PrimaryEglContext.MakeCurrent(surface);
var success = false;
try
{
if (IsCorrupted)
throw new RenderTargetCorruptedException();
var restoreContext = _context.MakeCurrent(surface);
_display.EglInterface.WaitClient();
_display.EglInterface.WaitGL();
_display.EglInterface.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE);
return new Session(_display, _context, surface, info, l, restoreContext, onFinish, isYFlipped);
var egli = _egl.Display.EglInterface;
egli.WaitClient();
egli.WaitGL();
egli.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE);
_egl.PrimaryContext.GlInterface.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
success = true;
return new Session(_egl.Display, _egl.PrimaryEglContext, surface, info, restoreContext, onFinish, isYFlipped);
}
catch
finally
{
l.Dispose();
throw;
if(!success)
restoreContext.Dispose();
}
}
@ -62,21 +62,19 @@ namespace Avalonia.OpenGL
private readonly EglSurface _glSurface;
private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info;
private readonly EglDisplay _display;
private readonly IDisposable _lock;
private readonly IDisposable _restoreContext;
private readonly Action _onFinish;
public Session(EglDisplay display, EglContext context,
EglSurface glSurface, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock, IDisposable restoreContext, Action onFinish, bool isYFlipped)
IDisposable restoreContext, Action onFinish, bool isYFlipped)
{
IsYFlipped = isYFlipped;
_context = context;
_display = display;
_glSurface = glSurface;
_info = info;
_lock = @lock;
_restoreContext = restoreContext;
_onFinish = onFinish;
}
@ -90,7 +88,6 @@ namespace Avalonia.OpenGL
_display.EglInterface.WaitGL();
_display.EglInterface.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE);
_restoreContext.Dispose();
_lock.Dispose();
_onFinish?.Invoke();
}

2
src/Avalonia.OpenGL/EglInterface.cs → src/Avalonia.OpenGL/Egl/EglInterface.cs

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglInterface : GlInterfaceBase
{

72
src/Avalonia.OpenGL/Egl/EglPlatformOpenGlInterface.cs

@ -0,0 +1,72 @@
using System;
using Avalonia.Logging;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL.Egl
{
public class EglPlatformOpenGlInterface : IPlatformOpenGlInterface
{
public EglDisplay Display { get; private set; }
public bool CanCreateContexts => true;
public bool CanShareContexts => Display.SupportsSharing;
public EglContext PrimaryEglContext { get; }
public IGlContext PrimaryContext => PrimaryEglContext;
public EglPlatformOpenGlInterface(EglDisplay display)
{
Display = display;
PrimaryEglContext = display.CreateContext(null);
}
public static void TryInitialize()
{
var feature = TryCreate();
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToConstant(feature);
}
public static EglPlatformOpenGlInterface TryCreate() => TryCreate(() => new EglDisplay());
public static EglPlatformOpenGlInterface TryCreate(Func<EglDisplay> displayFactory)
{
try
{
return new EglPlatformOpenGlInterface(displayFactory());
}
catch(Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log(null, "Unable to initialize EGL-based rendering: {0}", e);
return null;
}
}
public IGlContext CreateContext() => Display.CreateContext(null);
public IGlContext CreateSharedContext() => Display.CreateContext(PrimaryEglContext);
public EglSurface CreateWindowSurface(IntPtr window)
{
using (PrimaryContext.MakeCurrent())
{
var s = Display.EglInterface.CreateWindowSurface(Display.Handle, Display.Config, window,
new[] { EGL_NONE, EGL_NONE });
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", Display.EglInterface);
return new EglSurface(Display, PrimaryEglContext, s);
}
}
public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs)
{
using (PrimaryContext.MakeCurrent())
{
var s = Display.EglInterface.CreatePbufferFromClientBuffer(Display.Handle, bufferType, handle,
Display.Config, attribs);
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePbufferFromClientBuffer", Display.EglInterface);
return new EglSurface(Display, PrimaryEglContext, s);
}
}
}
}

11
src/Avalonia.OpenGL/EglSurface.cs → src/Avalonia.OpenGL/Egl/EglSurface.cs

@ -1,22 +1,25 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglSurface : SafeHandle
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglInterface _egl;
public EglSurface(EglDisplay display, EglInterface egl, IntPtr surface) : base(surface, true)
public EglSurface(EglDisplay display, EglContext context, IntPtr surface) : base(surface, true)
{
_display = display;
_egl = egl;
_context = context;
_egl = display.EglInterface;
}
protected override bool ReleaseHandle()
{
_egl.DestroySurface(_display.Handle, handle);
using (_context.MakeCurrent())
_egl.DestroySurface(_display.Handle, handle);
return true;
}

43
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -1,43 +0,0 @@
using System;
using Avalonia.Logging;
namespace Avalonia.OpenGL
{
public class EglGlPlatformFeature : IWindowingPlatformGlFeature
{
private EglDisplay _display;
public EglDisplay Display => _display;
public IGlContext CreateContext()
{
return _display.CreateContext(DeferredContext);
}
public EglContext DeferredContext { get; private set; }
public IGlContext MainContext => DeferredContext;
public static void TryInitialize()
{
var feature = TryCreate();
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
}
public static EglGlPlatformFeature TryCreate() => TryCreate(() => new EglDisplay());
public static EglGlPlatformFeature TryCreate(Func<EglDisplay> displayFactory)
{
try
{
var disp = displayFactory();
return new EglGlPlatformFeature
{
_display = disp,
DeferredContext = disp.CreateContext(null)
};
}
catch(Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log(null, "Unable to initialize EGL-based rendering: {0}", e);
return null;
}
}
}
}

51
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -1,51 +0,0 @@
using System;
using System.Threading;
namespace Avalonia.OpenGL
{
public class EglGlPlatformSurface : EglGlPlatformSurfaceBase
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglContext context, IEglWindowGlPlatformSurfaceInfo info) : base()
{
_display = context.Display;
_context = context;
_info = info;
}
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
var glSurface = _display.CreateWindowSurface(_info.Handle);
return new RenderTarget(_display, _context, glSurface, _info);
}
class RenderTarget : EglPlatformSurfaceRenderTargetBase
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _initialSize;
public RenderTarget(EglDisplay display, EglContext context,
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) : base(display, context)
{
_display = display;
_context = context;
_glSurface = glSurface;
_info = info;
_initialSize = info.Size;
}
public override void Dispose() => _glSurface.Dispose();
public override bool IsCorrupted => _initialSize != _info.Size;
public override IGlPlatformSurfaceRenderingSession BeginDraw() => base.BeginDraw(_glSurface, _info);
}
}
}

13
src/Avalonia.OpenGL/GlInterface.cs

@ -82,6 +82,9 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glFlush")]
public Action Flush { get; }
[GlEntryPoint("glFinish")]
public Action Finish { get; }
public delegate IntPtr GlGetString(int v);
[GlEntryPoint("glGetString")]
@ -144,6 +147,10 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glBindTexture")]
public GlBindTexture BindTexture { get; }
public delegate void GlActiveTexture(int texture);
[GlEntryPoint("glActiveTexture")]
public GlActiveTexture ActiveTexture { get; }
public delegate void GlDeleteTextures(int count, int[] textures);
[GlEntryPoint("glDeleteTextures")]
public GlDeleteTextures DeleteTextures { get; }
@ -154,6 +161,12 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glTexImage2D")]
public GlTexImage2D TexImage2D { get; }
public delegate void GlCopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y,
int width, int height);
[GlEntryPoint("glCopyTexSubImage2D")]
public GlCopyTexSubImage2D CopyTexSubImage2D { get; }
public delegate void GlTexParameteri(int target, int name, int value);
[GlEntryPoint("glTexParameteri")]
public GlTexParameteri TexParameteri { get; }

2
src/Avalonia.OpenGL/IGlContext.cs

@ -9,5 +9,7 @@ namespace Avalonia.OpenGL
int SampleCount { get; }
int StencilSize { get; }
IDisposable MakeCurrent();
IDisposable EnsureCurrent();
bool IsSharedWith(IGlContext context);
}
}

2
src/Avalonia.OpenGL/IOpenGlAwarePlatformRenderInterface.cs

@ -4,6 +4,6 @@ namespace Avalonia.OpenGL
{
public interface IOpenGlAwarePlatformRenderInterface
{
IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap();
IOpenGlBitmapImpl CreateOpenGlBitmap(PixelSize size, Vector dpi);
}
}

13
src/Avalonia.OpenGL/IPlatformOpenGlInterface.cs

@ -0,0 +1,13 @@
namespace Avalonia.OpenGL
{
public interface IPlatformOpenGlInterface
{
IGlContext PrimaryContext { get; }
IGlContext CreateSharedContext();
bool CanShareContexts { get; }
bool CanCreateContexts { get; }
IGlContext CreateContext();
/*IGlContext TryCreateContext(GlVersion version);
*/
}
}

8
src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs

@ -1,8 +0,0 @@
namespace Avalonia.OpenGL
{
public interface IWindowingPlatformGlFeature
{
IGlContext CreateContext();
IGlContext MainContext { get; }
}
}

17
src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs

@ -0,0 +1,17 @@
using System;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace Avalonia.OpenGL.Imaging
{
public interface IOpenGlBitmapImpl : IBitmapImpl
{
IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context, Action presentCallback);
bool SupportsContext(IGlContext context);
}
public interface IOpenGlBitmapAttachment : IDisposable
{
void Present();
}
}

13
src/Avalonia.OpenGL/Imaging/IOpenGlTextureBitmapImpl.cs

@ -1,13 +0,0 @@
using System;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace Avalonia.OpenGL.Imaging
{
public interface IOpenGlTextureBitmapImpl : IBitmapImpl
{
IDisposable Lock();
void SetBackBuffer(int textureId, int internalFormat, PixelSize pixelSize, double dpiScaling);
void SetDirty();
}
}

34
src/Avalonia.OpenGL/Imaging/OpenGlTextureBitmap.cs → src/Avalonia.OpenGL/Imaging/OpenGlBitmap.cs

@ -6,32 +6,30 @@ using Avalonia.Threading;
namespace Avalonia.OpenGL.Imaging
{
public class OpenGlTextureBitmap : Bitmap, IAffectsRender
public class OpenGlBitmap : Bitmap, IAffectsRender
{
private IOpenGlTextureBitmapImpl _impl;
static IOpenGlTextureBitmapImpl CreateOrThrow()
private IOpenGlBitmapImpl _impl;
public OpenGlBitmap(PixelSize size, Vector dpi)
: base(CreateOrThrow(size, dpi))
{
if (!(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() is IOpenGlAwarePlatformRenderInterface
glAware))
throw new PlatformNotSupportedException("Rendering platform does not support OpenGL integration");
return glAware.CreateOpenGlTextureBitmap();
_impl = (IOpenGlBitmapImpl)PlatformImpl.Item;
}
public OpenGlTextureBitmap()
: base(CreateOrThrow())
static IOpenGlBitmapImpl CreateOrThrow(PixelSize size, Vector dpi)
{
_impl = (IOpenGlTextureBitmapImpl)PlatformImpl.Item;
if (!(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() is IOpenGlAwarePlatformRenderInterface
glAware))
throw new PlatformNotSupportedException("Rendering platform does not support OpenGL integration");
return glAware.CreateOpenGlBitmap(size, dpi);
}
public IDisposable Lock() => _impl.Lock();
public IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context) =>
_impl.CreateFramebufferAttachment(context, SetIsDirty);
public void SetTexture(int textureId, int internalFormat, PixelSize size, double dpiScaling)
{
_impl.SetBackBuffer(textureId, internalFormat, size, dpiScaling);
SetIsDirty();
}
public void SetIsDirty()
public bool SupportsContext(IGlContext context) => _impl.SupportsContext(context);
void SetIsDirty()
{
if (Dispatcher.UIThread.CheckAccess())
CallInvalidated();

1
src/Avalonia.OpenGL/OpenGlException.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.OpenGL.Egl;
namespace Avalonia.OpenGL
{

2
src/Avalonia.OpenGL/IGlPlatformSurface.cs → src/Avalonia.OpenGL/Surfaces/IGlPlatformSurface.cs

@ -1,4 +1,4 @@
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Surfaces
{
public interface IGlPlatformSurface
{

2
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderTarget.cs → src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs

@ -1,6 +1,6 @@
using System;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Surfaces
{
public interface IGlPlatformSurfaceRenderTarget : IDisposable
{

2
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs → src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderingSession.cs

@ -1,6 +1,6 @@
using System;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Surfaces
{
public interface IGlPlatformSurfaceRenderingSession : IDisposable
{

18
src/Avalonia.Styling/Controls/Metadata/PseudoClassesAttribute.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
#nullable enable
namespace Avalonia.Controls.Metadata
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class PseudoClassesAttribute : Attribute
{
public PseudoClassesAttribute(params string[] pseudoClasses)
{
PseudoClasses = pseudoClasses;
}
public IReadOnlyList<string> PseudoClasses { get; }
}
}

3
src/Avalonia.Themes.Default/Accents/BaseDark.xaml

@ -72,5 +72,8 @@
<sys:Double x:Key="ScrollBarThickness">18</sys:Double>
<sys:Double x:Key="ScrollBarThumbThickness">8</sys:Double>
<sys:Double x:Key="IconElementThemeHeight">20</sys:Double>
<sys:Double x:Key="IconElementThemeWidth">20</sys:Double>
</Style.Resources>
</Style>

3
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@ -75,5 +75,8 @@
<sys:Double x:Key="ScrollBarThickness">18</sys:Double>
<sys:Double x:Key="ScrollBarThumbThickness">8</sys:Double>
<sys:Double x:Key="IconElementThemeHeight">20</sys:Double>
<sys:Double x:Key="IconElementThemeWidth">20</sys:Double>
</Style.Resources>
</Style>

3
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -12,7 +12,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.CaptionButtons.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ComboBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ComboBoxItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ContentControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ContentControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.GridSplitter.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ItemsControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ListBox.xaml?assembly=Avalonia.Themes.Default"/>
@ -21,6 +21,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.ContextMenu.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.MenuItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.OverlayPopupHost.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.PathIcon.xaml?assembly=Avalonia.Themes.Default" />
<StyleInclude Source="resm:Avalonia.Themes.Default.PopupRoot.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ProgressBar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.RadioButton.xaml?assembly=Avalonia.Themes.Default"/>

17
src/Avalonia.Themes.Default/PathIcon.xaml

@ -0,0 +1,17 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="PathIcon">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
<Setter Property="Height" Value="16" />
<Setter Property="Width" Value="16" />
<Setter Property="Template">
<ControlTemplate>
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}" />
</Viewbox>
</ControlTemplate>
</Setter>
</Style>
</Styles>

2
src/Avalonia.Themes.Fluent/Accents/Base.xaml

@ -20,5 +20,7 @@
<Thickness x:Key="TextControlBorderThemeThickness">1</Thickness>
<Thickness x:Key="TextControlBorderThemeThicknessFocused">2</Thickness>
<Thickness x:Key="TextControlThemePadding">10,6,6,5</Thickness>
<sys:Double x:Key="IconElementThemeHeight">20</sys:Double>
<sys:Double x:Key="IconElementThemeWidth">20</sys:Double>
</Style.Resources>
</Style>

4
src/Avalonia.Themes.Fluent/Button.xaml

@ -77,7 +77,7 @@
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
</Style>
<Style Selector="Button">
<Style Selector="Button, RepeatButton, ToggleButton">
<Setter Property="RenderTransform" Value="none" />
<Setter Property="Transitions">
<Transitions>
@ -86,7 +86,7 @@
</Setter>
</Style>
<Style Selector="Button:pressed">
<Style Selector="Button:pressed, RepeatButton:pressed, ToggleButton:pressed">
<Setter Property="RenderTransform" Value="scale(0.98)" />
</Style>

3
src/Avalonia.Themes.Fluent/FluentTheme.xaml

@ -11,7 +11,7 @@
<StyleInclude Source="avares://Avalonia.Themes.Fluent/CheckBox.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ComboBox.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ComboBoxItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ContentControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ContentControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/GridSplitter.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ItemsControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ListBox.xaml"/>
@ -20,6 +20,7 @@
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ContextMenu.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/MenuItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/OverlayPopupHost.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/PathIcon.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Fluent/PopupRoot.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ProgressBar.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/RadioButton.xaml"/>

25
src/Avalonia.Themes.Fluent/PathIcon.xaml

@ -0,0 +1,25 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<StackPanel>
<StackPanel.Resources>
<StreamGeometry x:Key="settings_regular">M14 9.50006C11.5147 9.50006 9.5 11.5148 9.5 14.0001C9.5 16.4853 11.5147 18.5001 14 18.5001C15.3488 18.5001 16.559 17.9066 17.3838 16.9666C18.0787 16.1746 18.5 15.1365 18.5 14.0001C18.5 13.5401 18.431 13.0963 18.3028 12.6784C17.7382 10.8381 16.0253 9.50006 14 9.50006ZM11 14.0001C11 12.3432 12.3431 11.0001 14 11.0001C15.6569 11.0001 17 12.3432 17 14.0001C17 15.6569 15.6569 17.0001 14 17.0001C12.3431 17.0001 11 15.6569 11 14.0001Z M21.7093 22.3948L19.9818 21.6364C19.4876 21.4197 18.9071 21.4515 18.44 21.7219C17.9729 21.9924 17.675 22.4693 17.6157 23.0066L17.408 24.8855C17.3651 25.273 17.084 25.5917 16.7055 25.682C14.9263 26.1061 13.0725 26.1061 11.2933 25.682C10.9148 25.5917 10.6336 25.273 10.5908 24.8855L10.3834 23.0093C10.3225 22.4731 10.0112 21.9976 9.54452 21.7281C9.07783 21.4586 8.51117 21.4269 8.01859 21.6424L6.29071 22.4009C5.93281 22.558 5.51493 22.4718 5.24806 22.1859C4.00474 20.8536 3.07924 19.2561 2.54122 17.5137C2.42533 17.1384 2.55922 16.7307 2.8749 16.4977L4.40219 15.3703C4.83721 15.0501 5.09414 14.5415 5.09414 14.0007C5.09414 13.4598 4.83721 12.9512 4.40162 12.6306L2.87529 11.5051C2.55914 11.272 2.42513 10.8638 2.54142 10.4882C3.08038 8.74734 4.00637 7.15163 5.24971 5.82114C5.51684 5.53528 5.93492 5.44941 6.29276 5.60691L8.01296 6.36404C8.50793 6.58168 9.07696 6.54881 9.54617 6.27415C10.0133 6.00264 10.3244 5.52527 10.3844 4.98794L10.5933 3.11017C10.637 2.71803 10.9245 2.39704 11.3089 2.31138C12.19 2.11504 13.0891 2.01071 14.0131 2.00006C14.9147 2.01047 15.8128 2.11485 16.6928 2.31149C17.077 2.39734 17.3643 2.71823 17.4079 3.11017L17.617 4.98937C17.7116 5.85221 18.4387 6.50572 19.3055 6.50663C19.5385 6.507 19.769 6.45838 19.9843 6.36294L21.7048 5.60568C22.0626 5.44818 22.4807 5.53405 22.7478 5.81991C23.9912 7.1504 24.9172 8.74611 25.4561 10.487C25.5723 10.8623 25.4386 11.2703 25.1228 11.5035L23.5978 12.6297C23.1628 12.95 22.9 13.4586 22.9 13.9994C22.9 14.5403 23.1628 15.0489 23.5988 15.3698L25.1251 16.4965C25.441 16.7296 25.5748 17.1376 25.4586 17.5131C24.9198 19.2536 23.9944 20.8492 22.7517 22.1799C22.4849 22.4657 22.0671 22.5518 21.7093 22.3948ZM16.263 22.1966C16.4982 21.4685 16.9889 20.8288 17.6884 20.4238C18.5702 19.9132 19.6536 19.8547 20.5841 20.2627L21.9281 20.8526C22.791 19.8538 23.4593 18.7013 23.8981 17.4552L22.7095 16.5778L22.7086 16.5771C21.898 15.98 21.4 15.0277 21.4 13.9994C21.4 12.9719 21.8974 12.0195 22.7073 11.4227L22.7085 11.4218L23.8957 10.545C23.4567 9.2988 22.7881 8.14636 21.9248 7.1477L20.5922 7.73425L20.5899 7.73527C20.1844 7.91463 19.7472 8.00722 19.3039 8.00663C17.6715 8.00453 16.3046 6.77431 16.1261 5.15465L16.1259 5.15291L15.9635 3.69304C15.3202 3.57328 14.6677 3.50872 14.013 3.50017C13.3389 3.50891 12.6821 3.57367 12.0377 3.69328L11.8751 5.15452C11.7625 6.16272 11.1793 7.05909 10.3019 7.56986C9.41937 8.0856 8.34453 8.14844 7.40869 7.73694L6.07273 7.14893C5.20949 8.14751 4.54092 9.29983 4.10196 10.5459L5.29181 11.4233C6.11115 12.0269 6.59414 12.9837 6.59414 14.0007C6.59414 15.0173 6.11142 15.9742 5.29237 16.5776L4.10161 17.4566C4.54002 18.7044 5.2085 19.8585 6.07205 20.8587L7.41742 20.2682C8.34745 19.8613 9.41573 19.9215 10.2947 20.4292C11.174 20.937 11.7593 21.832 11.8738 22.84L11.8744 22.8445L12.0362 24.3088C13.3326 24.5638 14.6662 24.5638 15.9626 24.3088L16.1247 22.8418C16.1491 22.6217 16.1955 22.4055 16.263 22.1966Z</StreamGeometry>
</StackPanel.Resources>
<PathIcon Data="{StaticResource settings_regular}" />
</StackPanel>
</Design.PreviewWith>
<Style Selector="PathIcon">
<Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
<Setter Property="Height" Value="16" />
<Setter Property="Width" Value="16" />
<Setter Property="Template">
<ControlTemplate>
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}" />
</Viewbox>
</ControlTemplate>
</Setter>
</Style>
</Styles>

20
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -1,15 +1,33 @@
Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.GlyphRunDrawing.BaselineOrigin.set(Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotSealType : Type 'Avalonia.Media.Typeface' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract.
TypeCannotChangeClassification : Type 'Avalonia.Media.Typeface' is a 'struct' in the implementation but is a 'class' in the contract.
CannotMakeMemberNonVirtual : Member 'public System.Boolean Avalonia.Media.Typeface.Equals(System.Object)' is non-virtual in the implementation but is virtual in the contract.
CannotMakeMemberNonVirtual : Member 'public System.Int32 Avalonia.Media.Typeface.GetHashCode()' is non-virtual in the implementation but is virtual in the contract.
TypesMustExist : Type 'Avalonia.Media.Fonts.FontKey' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.DrawableTextRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size.get()' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.ShapedTextCharacters.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.ShapedTextCharacters.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLayout.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak' is abstract in the implementation but is missing in the contract.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.LineBreak.get()' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak.get()' is abstract in the implementation but is missing in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
Total Issues: 13
Total Issues: 31

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save