diff --git a/Avalonia.sln b/Avalonia.sln index 4999719676..35b6b2108a 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -13,7 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\W EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Default", "src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Simple", "src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Diagnostics", "src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}" EndProject diff --git a/azure-pipelines.yml b/azure-pipelines.yml index edf3c3d819..52fc8db53c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -59,7 +59,7 @@ jobs: variables: SolutionDir: '$(Build.SourcesDirectory)' pool: - vmImage: 'macOS-10.15' + vmImage: 'macos-12' steps: - task: UseDotNet@2 displayName: 'Use .NET Core SDK 3.1.418' @@ -91,10 +91,10 @@ jobs: inputs: actions: 'build' scheme: '' - sdk: 'macosx11.1' + sdk: 'macosx12.3' configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' - xcodeVersion: '12' # Options: 8, 9, default, specifyPath + xcodeVersion: '13' # Options: 8, 9, default, specifyPath args: '-derivedDataPath ./' - task: CmdLine@2 diff --git a/samples/BindingDemo/App.xaml b/samples/BindingDemo/App.xaml index 3e312c8685..175e838616 100644 --- a/samples/BindingDemo/App.xaml +++ b/samples/BindingDemo/App.xaml @@ -4,6 +4,6 @@ x:Class="BindingDemo.App"> - + diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs index 7ebb87094a..750c1082a6 100644 --- a/samples/ControlCatalog/App.xaml.cs +++ b/samples/ControlCatalog/App.xaml.cs @@ -5,7 +5,7 @@ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml.Styling; using Avalonia.Styling; -using Avalonia.Themes.Default; +using Avalonia.Themes.Simple; using Avalonia.Themes.Fluent; using ControlCatalog.ViewModels; @@ -23,9 +23,9 @@ namespace ControlCatalog Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml") }; - public static readonly StyleInclude ColorPickerDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) + public static readonly StyleInclude ColorPickerSimple = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) { - Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml") + Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml") }; public static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) @@ -33,16 +33,16 @@ namespace ControlCatalog Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml") }; - public static readonly StyleInclude DataGridDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) + public static readonly StyleInclude DataGridSimple = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) { - Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Default.xaml") + Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Simple.xaml") }; public static FluentTheme Fluent = new FluentTheme(new Uri("avares://ControlCatalog/Styles")); - public static SimpleTheme Default = new SimpleTheme(new Uri("avares://ControlCatalog/Styles")); + public static SimpleTheme Simple = new SimpleTheme(new Uri("avares://ControlCatalog/Styles")); - public static Styles DefaultLight = new Styles + public static Styles SimpleLight = new Styles { new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) { @@ -56,10 +56,10 @@ namespace ControlCatalog { Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseLight.xaml") }, - Default + Simple }; - public static Styles DefaultDark = new Styles + public static Styles SimpleDark = new Styles { new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) { @@ -73,7 +73,7 @@ namespace ControlCatalog { Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseDark.xaml") }, - Default + Simple }; public override void Initialize() diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index 8358fb3cd4..2654574a3e 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -29,7 +29,7 @@ - + diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 7461e78c33..7f5a191519 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -187,8 +187,8 @@ FluentLight FluentDark - DefaultLight - DefaultDark + SimpleLight + SimpleDark + + + - @@ -54,7 +54,8 @@ - diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index f7b6db1255..036dccde0e 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -195,10 +195,10 @@ namespace ControlCatalog.Pages { // Sync disposal of StreamWriter is not supported on WASM #if NET6_0_OR_GREATER - await using var stream = await file.OpenWrite(); + await using var stream = await file.OpenWriteAsync(); await using var reader = new System.IO.StreamWriter(stream); #else - using var stream = await file.OpenWrite(); + using var stream = await file.OpenWriteAsync(); using var reader = new System.IO.StreamWriter(stream); #endif await reader.WriteLineAsync(openedFileContent.Text); @@ -243,8 +243,8 @@ namespace ControlCatalog.Pages async Task SetPickerResult(IReadOnlyCollection? items) { items ??= Array.Empty(); - var mappedResults = items.Select(FullPathOrName).ToList(); - bookmarkContainer.Text = items.FirstOrDefault(f => f.CanBookmark) is { } f ? await f.SaveBookmark() : "Can't bookmark"; + bookmarkContainer.Text = items.FirstOrDefault(f => f.CanBookmark) is { } f ? await f.SaveBookmarkAsync() : "Can't bookmark"; + var mappedResults = new List(); if (items.FirstOrDefault() is IStorageItem item) { @@ -267,9 +267,9 @@ Content: if (file.CanOpenRead) { #if NET6_0_OR_GREATER - await using var stream = await file.OpenRead(); + await using var stream = await file.OpenReadAsync(); #else - using var stream = await file.OpenRead(); + using var stream = await file.OpenReadAsync(); #endif using var reader = new System.IO.StreamReader(stream); @@ -293,7 +293,19 @@ Content: lastSelectedDirectory = await item.GetParentAsync(); if (lastSelectedDirectory is not null) { - mappedResults.Insert(0, "Parent: " + FullPathOrName(lastSelectedDirectory)); + mappedResults.Add(FullPathOrName(lastSelectedDirectory)); + } + + foreach (var selectedItem in items) + { + mappedResults.Add("+> " + FullPathOrName(selectedItem)); + if (selectedItem is IStorageFolder folder) + { + foreach (var innerItems in await folder.GetItemsAsync()) + { + mappedResults.Add("++> " + FullPathOrName(innerItems)); + } + } } } diff --git a/samples/PlatformSanityChecks/App.xaml b/samples/PlatformSanityChecks/App.xaml index 25bab6ae35..1b9d64fca6 100644 --- a/samples/PlatformSanityChecks/App.xaml +++ b/samples/PlatformSanityChecks/App.xaml @@ -1,6 +1,5 @@ - - + diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj index 4f7f06b529..5c743aabdb 100644 --- a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj +++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/Previewer/App.xaml b/samples/Previewer/App.xaml index 6bae1955af..1b9d64fca6 100644 --- a/samples/Previewer/App.xaml +++ b/samples/Previewer/App.xaml @@ -1,6 +1,5 @@ - - + - \ No newline at end of file + diff --git a/samples/Previewer/Previewer.csproj b/samples/Previewer/Previewer.csproj index 98560e9ab0..2cc84168dc 100644 --- a/samples/Previewer/Previewer.csproj +++ b/samples/Previewer/Previewer.csproj @@ -10,7 +10,7 @@ - + diff --git a/samples/VirtualizationDemo/App.xaml b/samples/VirtualizationDemo/App.xaml index 3ad1dce794..eb5f0e4dca 100644 --- a/samples/VirtualizationDemo/App.xaml +++ b/samples/VirtualizationDemo/App.xaml @@ -1,9 +1,7 @@ - - - - - - \ No newline at end of file + + + + + diff --git a/samples/VirtualizationDemo/VirtualizationDemo.csproj b/samples/VirtualizationDemo/VirtualizationDemo.csproj index bd6054327f..b27cfe77e8 100644 --- a/samples/VirtualizationDemo/VirtualizationDemo.csproj +++ b/samples/VirtualizationDemo/VirtualizationDemo.csproj @@ -5,7 +5,7 @@ - + diff --git a/samples/interop/Direct3DInteropSample/App.paml b/samples/interop/Direct3DInteropSample/App.paml index d9630eef58..e6d77dfaf4 100644 --- a/samples/interop/Direct3DInteropSample/App.paml +++ b/samples/interop/Direct3DInteropSample/App.paml @@ -1,6 +1,5 @@ - - + - \ No newline at end of file + diff --git a/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj b/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj index 81b94b4d09..f9ef4693d5 100644 --- a/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj +++ b/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs index 50581d47b1..a9b2e16d43 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs @@ -1,6 +1,7 @@ #nullable enable using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -35,13 +36,13 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem public bool CanBookmark => true; - public Task SaveBookmark() + public Task SaveBookmarkAsync() { Context.ContentResolver?.TakePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission); return Task.FromResult(Uri.ToString()); } - public Task ReleaseBookmark() + public Task ReleaseBookmarkAsync() { Context.ContentResolver?.ReleasePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission); return Task.CompletedTask; @@ -106,6 +107,30 @@ internal sealed class AndroidStorageFolder : AndroidStorageItem, IStorageBookmar { return Task.FromResult(new StorageItemProperties()); } + + public async Task> GetItemsAsync() + { + using var javaFile = new JavaFile(Uri.Path!); + + // Java file represents files AND directories. Don't be confused. + var files = await javaFile.ListFilesAsync().ConfigureAwait(false); + if (files is null) + { + return Array.Empty(); + } + + return files + .Select(f => (file: f, uri: AndroidUri.FromFile(f))) + .Where(t => t.uri is not null) + .Select(t => t.file switch + { + { IsFile: true } => (IStorageItem)new AndroidStorageFile(Context, t.uri!), + { IsDirectory: true } => new AndroidStorageFolder(Context, t.uri!), + _ => null + }) + .Where(i => i is not null) + .ToArray()!; + } } internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkFile @@ -118,10 +143,10 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF public bool CanOpenWrite => true; - public Task OpenRead() => Task.FromResult(OpenContentStream(Context, Uri, false) + public Task OpenReadAsync() => Task.FromResult(OpenContentStream(Context, Uri, false) ?? throw new InvalidOperationException("Failed to open content stream")); - public Task OpenWrite() => Task.FromResult(OpenContentStream(Context, Uri, true) + public Task OpenWriteAsync() => Task.FromResult(OpenContentStream(Context, Uri, true) ?? throw new InvalidOperationException("Failed to open content stream")); private Stream? OpenContentStream(Context context, AndroidUri uri, bool isOutput) diff --git a/src/Avalonia.Base/Controls/ResourceDictionary.cs b/src/Avalonia.Base/Controls/ResourceDictionary.cs index 77863e5101..d6197c50c6 100644 --- a/src/Avalonia.Base/Controls/ResourceDictionary.cs +++ b/src/Avalonia.Base/Controls/ResourceDictionary.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using Avalonia.Collections; +using Avalonia.Controls.Templates; namespace Avalonia.Controls { @@ -29,7 +30,11 @@ namespace Avalonia.Controls public object? this[object key] { - get => _inner?[key]; + get + { + TryGetValue(key, out var value); + return value; + } set { Inner[key] = value; @@ -119,6 +124,12 @@ namespace Avalonia.Controls Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty); } + public void AddDeferred(object key, Func factory) + { + Inner.Add(key, new DeferredItem(factory)); + Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty); + } + public void Clear() { if (_inner?.Count > 0) @@ -143,10 +154,8 @@ namespace Avalonia.Controls public bool TryGetResource(object key, out object? value) { - if (_inner is not null && _inner.TryGetValue(key, out value)) - { + if (TryGetValue(key, out value)) return true; - } if (_mergedDictionaries != null) { @@ -165,12 +174,28 @@ namespace Avalonia.Controls public bool TryGetValue(object key, out object? value) { - if (_inner is not null) - return _inner.TryGetValue(key, out value); + if (_inner is not null && _inner.TryGetValue(key, out value)) + { + if (value is DeferredItem deffered) + { + _inner[key] = value = deffered.Factory(null) switch + { + ITemplateResult t => t.Result, + object v => v, + _ => null, + }; + } + return true; + } + value = null; return false; } + public IEnumerator> GetEnumerator() + { + return _inner?.GetEnumerator() ?? Enumerable.Empty>().GetEnumerator(); + } void ICollection>.Add(KeyValuePair item) { @@ -198,12 +223,17 @@ namespace Avalonia.Controls return false; } - public IEnumerator> GetEnumerator() + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + internal bool ContainsDeferredKey(object key) { - return _inner?.GetEnumerator() ?? Enumerable.Empty>().GetEnumerator(); - } + if (_inner is not null && _inner.TryGetValue(key, out var result)) + { + return result is DeferredItem; + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + return false; + } void IResourceProvider.AddOwner(IResourceHost owner) { @@ -258,5 +288,11 @@ namespace Avalonia.Controls } } } + + private class DeferredItem + { + public DeferredItem(Func factory) => Factory = factory; + public Func Factory { get; } + } } } diff --git a/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs b/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs index 1758c45650..6121646107 100644 --- a/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs +++ b/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs @@ -132,6 +132,11 @@ namespace Avalonia.Controls { _target.OwnerChanged += OwnerChanged; _owner = _target.Owner; + + if (_owner is object) + { + _owner.ResourcesChanged += ResourcesChanged; + } } protected override void Deinitialize() diff --git a/src/Avalonia.Base/Controls/Templates/ITemplateResult.cs b/src/Avalonia.Base/Controls/Templates/ITemplateResult.cs new file mode 100644 index 0000000000..6bd4d735a7 --- /dev/null +++ b/src/Avalonia.Base/Controls/Templates/ITemplateResult.cs @@ -0,0 +1,8 @@ +namespace Avalonia.Controls.Templates +{ + public interface ITemplateResult + { + public object? Result { get; } + public INameScope NameScope { get; } + } +} diff --git a/src/Avalonia.Controls/Templates/TemplateResult.cs b/src/Avalonia.Base/Controls/Templates/TemplateResult.cs similarity index 80% rename from src/Avalonia.Controls/Templates/TemplateResult.cs rename to src/Avalonia.Base/Controls/Templates/TemplateResult.cs index 770aecc329..0e38c6c0ce 100644 --- a/src/Avalonia.Controls/Templates/TemplateResult.cs +++ b/src/Avalonia.Base/Controls/Templates/TemplateResult.cs @@ -1,9 +1,10 @@ namespace Avalonia.Controls.Templates { - public class TemplateResult + public class TemplateResult : ITemplateResult { public T Result { get; } public INameScope NameScope { get; } + object? ITemplateResult.Result => Result; public TemplateResult(T result, INameScope nameScope) { diff --git a/src/Avalonia.Base/Media/GlyphRun.cs b/src/Avalonia.Base/Media/GlyphRun.cs index 2a7f3360ad..cae7a8fe75 100644 --- a/src/Avalonia.Base/Media/GlyphRun.cs +++ b/src/Avalonia.Base/Media/GlyphRun.cs @@ -265,7 +265,7 @@ namespace Avalonia.Media //RightToLeft var glyphIndex = FindGlyphIndex(characterIndex); - if (GlyphClusters != null) + if (GlyphClusters != null && GlyphClusters.Count > 0) { if (characterIndex > GlyphClusters[0]) { diff --git a/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs b/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs index 97df87d3d9..7ab67ea34d 100644 --- a/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs +++ b/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Utilities; namespace Avalonia.Media.TextFormatting @@ -116,7 +117,30 @@ namespace Avalonia.Media.TextFormatting length = text.Length; } + length = CoerceLength(text, length); + return new ValueSpan(firstTextSourceIndex, length, currentProperties); } + + private static int CoerceLength(ReadOnlySlice text, int length) + { + var finalLength = 0; + + var graphemeEnumerator = new GraphemeEnumerator(text); + + while (graphemeEnumerator.MoveNext()) + { + var grapheme = graphemeEnumerator.Current; + + finalLength += grapheme.Text.Length; + + if (finalLength >= length) + { + return finalLength; + } + } + + return length; + } } } diff --git a/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs b/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs index df83ada34a..a49e4ef13b 100644 --- a/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs +++ b/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs @@ -15,6 +15,13 @@ namespace Avalonia.Media.TextFormatting public override void Justify(TextLine textLine) { + var lineImpl = textLine as TextLineImpl; + + if(lineImpl is null) + { + return; + } + var paragraphWidth = Width; if (double.IsInfinity(paragraphWidth)) @@ -22,12 +29,12 @@ namespace Avalonia.Media.TextFormatting return; } - if (textLine.NewLineLength > 0) + if (lineImpl.NewLineLength > 0) { return; } - var textLineBreak = textLine.TextLineBreak; + var textLineBreak = lineImpl.TextLineBreak; if (textLineBreak is not null && textLineBreak.TextEndOfLine is not null) { @@ -39,7 +46,7 @@ namespace Avalonia.Media.TextFormatting var breakOportunities = new Queue(); - foreach (var textRun in textLine.TextRuns) + foreach (var textRun in lineImpl.TextRuns) { var text = textRun.Text; @@ -68,10 +75,10 @@ namespace Avalonia.Media.TextFormatting return; } - var remainingSpace = Math.Max(0, paragraphWidth - textLine.WidthIncludingTrailingWhitespace); + var remainingSpace = Math.Max(0, paragraphWidth - lineImpl.WidthIncludingTrailingWhitespace); var spacing = remainingSpace / breakOportunities.Count; - foreach (var textRun in textLine.TextRuns) + foreach (var textRun in lineImpl.TextRuns) { var text = textRun.Text; diff --git a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs index ab72601c3e..42a9e61c36 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs @@ -38,7 +38,7 @@ namespace Avalonia.Media.TextFormatting /// Gets a list of . /// /// The shapeable text characters. - internal IReadOnlyList GetShapeableCharacters(ReadOnlySlice runText, sbyte biDiLevel, + internal IReadOnlyList GetShapeableCharacters(ReadOnlySlice runText, sbyte biDiLevel, ref TextRunProperties? previousProperties) { var shapeableCharacters = new List(2); @@ -65,7 +65,7 @@ namespace Avalonia.Media.TextFormatting /// The bidi level of the run. /// /// A list of shapeable text runs. - private static ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice text, + private static ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice text, TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties? previousProperties) { var defaultTypeface = defaultProperties.Typeface; @@ -76,7 +76,7 @@ namespace Avalonia.Media.TextFormatting { if (script == Script.Common && previousTypeface is not null) { - if(TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out var fallbackCount, out _)) + if (TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out var fallbackCount, out _)) { return new ShapeableTextCharacters(text.Take(fallbackCount), defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel); @@ -86,10 +86,10 @@ namespace Avalonia.Media.TextFormatting return new ShapeableTextCharacters(text.Take(count), defaultProperties.WithTypeface(currentTypeface), biDiLevel); } - + if (previousTypeface is not null) { - if(TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out count, out _)) + if (TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out count, out _)) { return new ShapeableTextCharacters(text.Take(count), defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel); @@ -106,12 +106,12 @@ namespace Avalonia.Media.TextFormatting { continue; } - + codepoint = codepointEnumerator.Current; - + break; } - + //ToDo: Fix FontFamily fallback var matchFound = FontManager.Current.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight, @@ -157,14 +157,14 @@ namespace Avalonia.Media.TextFormatting /// /// protected static bool TryGetShapeableLength( - ReadOnlySlice text, - Typeface typeface, + ReadOnlySlice text, + Typeface typeface, Typeface? defaultTypeface, out int length, out Script script) { length = 0; - script = Script.Unknown; + script = Script.Unknown; if (text.Length == 0) { @@ -182,7 +182,7 @@ namespace Avalonia.Media.TextFormatting var currentScript = currentGrapheme.FirstCodepoint.Script; - if (currentScript != Script.Common && defaultFont != null && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) + if (!currentGrapheme.FirstCodepoint.IsWhiteSpace && defaultFont != null && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } @@ -192,7 +192,7 @@ namespace Avalonia.Media.TextFormatting { break; } - + if (currentScript != script) { if (script is Script.Unknown || currentScript != Script.Common && diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs index f3e8b5969c..0828b6518a 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs @@ -537,8 +537,13 @@ namespace Avalonia.Media.TextFormatting /// /// The collapsing width. /// The . - private TextCollapsingProperties GetCollapsingProperties(double width) + private TextCollapsingProperties? GetCollapsingProperties(double width) { + if(_textTrimming == TextTrimming.None) + { + return null; + } + return _textTrimming.CreateCollapsingProperties(new TextCollapsingCreateInfo(width, _paragraphProperties.DefaultTextRunProperties)); } } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLine.cs b/src/Avalonia.Base/Media/TextFormatting/TextLine.cs index c8a23097db..61b24dc8c5 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLine.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLine.cs @@ -153,7 +153,7 @@ namespace Avalonia.Media.TextFormatting /// /// A value that represents a collapsed line that can be displayed. /// - public abstract TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList); + public abstract TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList); /// /// Create a justified line based on justification text properties. diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index f3c62f4994..fa1ab6fd29 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -119,7 +119,7 @@ namespace Avalonia.Media.TextFormatting } /// - public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) + public override TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList) { if (collapsingPropertiesList.Length == 0) { @@ -128,6 +128,11 @@ namespace Avalonia.Media.TextFormatting var collapsingProperties = collapsingPropertiesList[0]; + if(collapsingProperties is null) + { + return this; + } + var collapsedRuns = collapsingProperties.Collapse(this); if (collapsedRuns is null) @@ -171,7 +176,7 @@ namespace Avalonia.Media.TextFormatting return GetRunCharacterHit(firstRun, FirstTextSourceIndex, 0); } - if (distance > WidthIncludingTrailingWhitespace) + if (distance >= WidthIncludingTrailingWhitespace) { var lastRun = _textRuns[_textRuns.Count - 1]; @@ -183,8 +188,52 @@ namespace Avalonia.Media.TextFormatting var currentPosition = FirstTextSourceIndex; var currentDistance = 0.0; - foreach (var currentRun in _textRuns) + for (var i = 0; i < _textRuns.Count; i++) { + var currentRun = _textRuns[i]; + + if(currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) + { + var rightToLeftIndex = i; + currentPosition += currentRun.TextSourceLength; + + while (rightToLeftIndex + 1 <= _textRuns.Count - 1) + { + var nextShaped = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters; + + if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight) + { + break; + } + + currentPosition += nextShaped.TextSourceLength; + + rightToLeftIndex++; + } + + for (var j = i; i <= rightToLeftIndex; j++) + { + if(j > _textRuns.Count - 1) + { + break; + } + + currentRun = _textRuns[j]; + + if(currentDistance + currentRun.Size.Width <= distance) + { + currentDistance += currentRun.Size.Width; + currentPosition -= currentRun.TextSourceLength; + + continue; + } + + characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance); + + break; + } + } + if (currentDistance + currentRun.Size.Width < distance) { currentDistance += currentRun.Size.Width; @@ -211,12 +260,16 @@ namespace Avalonia.Media.TextFormatting { characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); - var offset = Math.Max(0, currentPosition - shapedRun.Text.Start); + var offset = 0; - if (!shapedRun.GlyphRun.IsLeftToRight) + if (shapedRun.GlyphRun.IsLeftToRight) { - offset = Math.Max(0, offset - shapedRun.Text.End); + offset = Math.Max(0, currentPosition - shapedRun.Text.Start); } + //else + //{ + // offset = Math.Max(0, currentPosition - shapedRun.Text.Start + shapedRun.Text.Length); + //} characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); @@ -255,10 +308,56 @@ namespace Avalonia.Media.TextFormatting { var currentRun = _textRuns[index]; - if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, - flowDirection, out var distance, out _)) + if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) + { + var i = index; + + var rightToLeftWidth = currentRun.Size.Width; + + while (i + 1 <= _textRuns.Count - 1) + { + var nextRun = _textRuns[i + 1]; + + if (nextRun is ShapedTextCharacters nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight) + { + i++; + + rightToLeftWidth += nextRun.Size.Width; + + continue; + } + + break; + } + + if(i > index) + { + while (i >= index) + { + currentRun = _textRuns[i]; + + rightToLeftWidth -= currentRun.Size.Width; + + if (currentPosition + currentRun.TextSourceLength >= characterIndex) + { + break; + } + + currentPosition += currentRun.TextSourceLength; + + remainingLength -= currentRun.TextSourceLength; + + i--; + } + + currentDistance += rightToLeftWidth; + } + } + + if (currentPosition + currentRun.TextSourceLength >= characterIndex && + TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, flowDirection, out var distance, out _)) { - return currentDistance + distance; + return Math.Max(0, currentDistance + distance); } //No hit hit found so we add the full width @@ -283,7 +382,7 @@ namespace Avalonia.Media.TextFormatting distance = currentGlyphRun.Size.Width - distance; } - return currentDistance - distance; + return Math.Max(0, currentDistance - distance); } //No hit hit found so we add the full width @@ -293,7 +392,7 @@ namespace Avalonia.Media.TextFormatting } } - return currentDistance; + return Math.Max(0, currentDistance); } private static bool TryGetDistanceFromCharacterHit( @@ -442,92 +541,139 @@ namespace Avalonia.Media.TextFormatting continue; } - if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) - { - startX += currentRun.Size.Width; - - currentPosition += currentRun.TextSourceLength; - - continue; - } - var characterLength = 0; var endX = startX; + var runWidth = 0.0; + TextRunBounds? currentRunBounds = null; - if (currentRun is ShapedTextCharacters currentShapedRun) + var currentShapedRun = currentRun as ShapedTextCharacters; + + if (currentShapedRun != null && !currentShapedRun.ShapedBuffer.IsLeftToRight) { - var offset = Math.Max(0, firstTextSourceIndex - currentPosition); + var rightToLeftIndex = index; + startX += currentShapedRun.Size.Width; - currentPosition += offset; + while (rightToLeftIndex + 1 <= _textRuns.Count - 1) + { + var nextShapedRun = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters; - var startIndex = currentRun.Text.Start + offset; + if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight) + { + break; + } - double startOffset; - double endOffset; + startX += nextShapedRun.Size.Width; - if (currentShapedRun.ShapedBuffer.IsLeftToRight) + rightToLeftIndex++; + } + + if (TryGetTextRunBoundsRightToLeft(startX, firstTextSourceIndex, characterIndex, rightToLeftIndex, ref currentPosition, ref remainingLength, out currentRunBounds)) { - startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); + startX = currentRunBounds!.Rectangle.Left; + endX = currentRunBounds.Rectangle.Right; - endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); + runWidth = currentRunBounds.Rectangle.Width; } - else + + currentDirection = FlowDirection.RightToLeft; + } + else + { + if (currentShapedRun != null) { - endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); + if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) + { + startX += currentRun.Size.Width; - if (currentPosition < startIndex) + currentPosition += currentRun.TextSourceLength; + + continue; + } + + var offset = Math.Max(0, firstTextSourceIndex - currentPosition); + + currentPosition += offset; + + var startIndex = currentRun.Text.Start + offset; + + double startOffset; + double endOffset; + + if (currentShapedRun.ShapedBuffer.IsLeftToRight) { - startOffset = endOffset; + startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); + + endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); } else { - startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); + endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); + + if (currentPosition < startIndex) + { + startOffset = endOffset; + } + else + { + startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); + } } - } - startX += startOffset; + startX += startOffset; - endX += endOffset; + endX += endOffset; - var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); - var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); + var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); + var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); - characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); + characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); - currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? - FlowDirection.LeftToRight : - FlowDirection.RightToLeft; - } - else - { - if (currentPosition < firstTextSourceIndex) + currentDirection = FlowDirection.LeftToRight; + } + else { - startX += currentRun.Size.Width; + if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) + { + startX += currentRun.Size.Width; + + currentPosition += currentRun.TextSourceLength; + + continue; + } + + if (currentPosition < firstTextSourceIndex) + { + startX += currentRun.Size.Width; + } + + if (currentPosition + currentRun.TextSourceLength <= characterIndex) + { + endX += currentRun.Size.Width; + + characterLength = currentRun.TextSourceLength; + } } - if (currentPosition + currentRun.TextSourceLength <= characterIndex) + if (endX < startX) { - endX += currentRun.Size.Width; + (endX, startX) = (startX, endX); + } - characterLength = currentRun.TextSourceLength; + //Lines that only contain a linebreak need to be covered here + if (characterLength == 0) + { + characterLength = NewLineLength; } - } - if (endX < startX) - { - (endX, startX) = (startX, endX); - } + runWidth = endX - startX; + currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); - //Lines that only contain a linebreak need to be covered here - if (characterLength == 0) - { - characterLength = NewLineLength; - } + currentPosition += characterLength; - var runWidth = endX - startX; - var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); + remainingLength -= characterLength; + } - if (!MathUtilities.IsZero(runWidth) || NewLineLength > 0) + if (currentRunBounds != null && !MathUtilities.IsZero(runWidth) || NewLineLength > 0) { if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) { @@ -537,32 +683,26 @@ namespace Avalonia.Media.TextFormatting textBounds.Rectangle = currentRect; - textBounds.TextRunBounds.Add(currentRunBounds); + textBounds.TextRunBounds.Add(currentRunBounds!); } else { - currentRect = currentRunBounds.Rectangle; + currentRect = currentRunBounds!.Rectangle; result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds })); } } currentWidth += runWidth; - currentPosition += characterLength; + - if (currentPosition > characterIndex) + if (remainingLength <= 0 || currentPosition >= characterIndex) { break; } startX = endX; lastDirection = currentDirection; - remainingLength -= characterLength; - - if (remainingLength <= 0) - { - break; - } } return result; @@ -674,7 +814,7 @@ namespace Avalonia.Media.TextFormatting var currentRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); - if(!MathUtilities.IsZero(runWidth) || NewLineLength > 0) + if (!MathUtilities.IsZero(runWidth) || NewLineLength > 0) { if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, Start + startX)) { @@ -692,7 +832,7 @@ namespace Avalonia.Media.TextFormatting result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds })); } - } + } currentWidth += runWidth; currentPosition += characterLength; @@ -716,6 +856,107 @@ namespace Avalonia.Media.TextFormatting return result; } + private bool TryGetTextRunBoundsRightToLeft(double startX, int firstTextSourceIndex, int characterIndex, int runIndex, ref int currentPosition, ref int remainingLength, out TextRunBounds? textRunBounds) + { + textRunBounds = null; + + for (var index = runIndex; index >= 0; index--) + { + if (TextRuns[index] is not DrawableTextRun currentRun) + { + continue; + } + + if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) + { + startX -= currentRun.Size.Width; + + currentPosition += currentRun.TextSourceLength; + + continue; + } + + var characterLength = 0; + var endX = startX; + + if (currentRun is ShapedTextCharacters currentShapedRun) + { + var offset = Math.Max(0, firstTextSourceIndex - currentPosition); + + currentPosition += offset; + + var startIndex = currentRun.Text.Start + offset; + double startOffset; + double endOffset; + + if (currentShapedRun.ShapedBuffer.IsLeftToRight) + { + if (currentPosition < startIndex) + { + startOffset = endOffset = 0; + } + else + { + endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); + + startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); + } + } + else + { + endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); + + startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); + } + + startX -= currentRun.Size.Width - startOffset; + endX -= currentRun.Size.Width - endOffset; + + var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); + var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); + + characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength); + } + else + { + if (currentPosition + currentRun.TextSourceLength <= characterIndex) + { + endX -= currentRun.Size.Width; + } + + if (currentPosition < firstTextSourceIndex) + { + startX -= currentRun.Size.Width; + + characterLength = currentRun.TextSourceLength; + } + } + + if (endX < startX) + { + (endX, startX) = (startX, endX); + } + + //Lines that only contain a linebreak need to be covered here + if (characterLength == 0) + { + characterLength = NewLineLength; + } + + var runWidth = endX - startX; + + remainingLength -= characterLength; + + currentPosition += characterLength; + + textRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); + + return true; + } + + return false; + } + public override IReadOnlyList GetTextBounds(int firstTextSourceIndex, int textLength) { if (_paragraphProperties.FlowDirection == FlowDirection.LeftToRight) @@ -1295,6 +1536,11 @@ namespace Avalonia.Media.TextFormatting var textAlignment = _paragraphProperties.TextAlignment; var paragraphFlowDirection = _paragraphProperties.FlowDirection; + if(textAlignment == TextAlignment.Justify) + { + textAlignment = TextAlignment.Start; + } + switch (textAlignment) { case TextAlignment.Start: @@ -1319,12 +1565,12 @@ namespace Avalonia.Media.TextFormatting case TextAlignment.Center: var start = (_paragraphWidth - width) / 2; - if(paragraphFlowDirection == FlowDirection.RightToLeft) + if (paragraphFlowDirection == FlowDirection.RightToLeft) { start -= (widthIncludingTrailingWhitespace - width); } - return Math.Max(0, start); + return Math.Max(0, start); case TextAlignment.Right: return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace); diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs index 56a90f31ea..ab17263806 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs @@ -224,7 +224,7 @@ namespace Avalonia.Media.TextFormatting.Unicode } /// - /// Returns if is between + /// Returns if is between /// and , inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Avalonia.Base/Platform/IGeometryImpl.cs b/src/Avalonia.Base/Platform/IGeometryImpl.cs index c80f8923ef..5826cfb2ff 100644 --- a/src/Avalonia.Base/Platform/IGeometryImpl.cs +++ b/src/Avalonia.Base/Platform/IGeometryImpl.cs @@ -38,8 +38,8 @@ namespace Avalonia.Platform /// Intersects the geometry with another geometry. /// /// The other geometry. - /// A new representing the intersection. - IGeometryImpl Intersect(IGeometryImpl geometry); + /// A new representing the intersection or null when the operation failed. + IGeometryImpl? Intersect(IGeometryImpl geometry); /// /// Indicates whether the geometry's stroke contains the specified point. diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs index 5af02219ce..cf21e9b8b5 100644 --- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs +++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs @@ -47,22 +47,22 @@ public class BclStorageFile : IStorageBookmarkFile return Task.FromResult(null); } - public Task OpenRead() + public Task OpenReadAsync() { return Task.FromResult(_fileInfo.OpenRead()); } - public Task OpenWrite() + public Task OpenWriteAsync() { return Task.FromResult(_fileInfo.OpenWrite()); } - public virtual Task SaveBookmark() + public virtual Task SaveBookmarkAsync() { return Task.FromResult(_fileInfo.FullName); } - public Task ReleaseBookmark() + public Task ReleaseBookmarkAsync() { // No-op return Task.CompletedTask; diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs index 7267017eaf..cd6c8be1ae 100644 --- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs +++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Linq; using System.Security; using System.Threading.Tasks; using Avalonia.Metadata; @@ -43,12 +45,22 @@ public class BclStorageFolder : IStorageBookmarkFolder return Task.FromResult(null); } - public virtual Task SaveBookmark() + public Task> GetItemsAsync() + { + var items = _directoryInfo.GetDirectories() + .Select(d => (IStorageItem)new BclStorageFolder(d)) + .Concat(_directoryInfo.GetFiles().Select(f => new BclStorageFile(f))) + .ToArray(); + + return Task.FromResult>(items); + } + + public virtual Task SaveBookmarkAsync() { return Task.FromResult(_directoryInfo.FullName); } - public Task ReleaseBookmark() + public Task ReleaseBookmarkAsync() { // No-op return Task.CompletedTask; diff --git a/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs b/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs index d21c950862..40f2720ee8 100644 --- a/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs +++ b/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs @@ -6,7 +6,7 @@ namespace Avalonia.Platform.Storage; [NotClientImplementable] public interface IStorageBookmarkItem : IStorageItem { - Task ReleaseBookmark(); + Task ReleaseBookmarkAsync(); } [NotClientImplementable] diff --git a/src/Avalonia.Base/Platform/Storage/IStorageFile.cs b/src/Avalonia.Base/Platform/Storage/IStorageFile.cs index 965caf8216..46aa6efa72 100644 --- a/src/Avalonia.Base/Platform/Storage/IStorageFile.cs +++ b/src/Avalonia.Base/Platform/Storage/IStorageFile.cs @@ -18,7 +18,7 @@ public interface IStorageFile : IStorageItem /// /// Opens a stream for read access. /// - Task OpenRead(); + Task OpenReadAsync(); /// /// Returns true, if file is writeable. @@ -28,5 +28,5 @@ public interface IStorageFile : IStorageItem /// /// Opens stream for writing to the file. /// - Task OpenWrite(); + Task OpenWriteAsync(); } diff --git a/src/Avalonia.Base/Platform/Storage/IStorageFolder.cs b/src/Avalonia.Base/Platform/Storage/IStorageFolder.cs index 25b9f01a92..0ffb9f41c6 100644 --- a/src/Avalonia.Base/Platform/Storage/IStorageFolder.cs +++ b/src/Avalonia.Base/Platform/Storage/IStorageFolder.cs @@ -1,4 +1,6 @@ -using Avalonia.Metadata; +using System.Collections.Generic; +using System.Threading.Tasks; +using Avalonia.Metadata; namespace Avalonia.Platform.Storage; @@ -8,4 +10,11 @@ namespace Avalonia.Platform.Storage; [NotClientImplementable] public interface IStorageFolder : IStorageItem { + /// + /// Gets the files and subfolders in the current folder. + /// + /// + /// When this method completes successfully, it returns a list of the files and folders in the current folder. Each item in the list is represented by an implementation object. + /// + Task> GetItemsAsync(); } diff --git a/src/Avalonia.Base/Platform/Storage/IStorageItem.cs b/src/Avalonia.Base/Platform/Storage/IStorageItem.cs index 8513ebc7d9..f5469d31c9 100644 --- a/src/Avalonia.Base/Platform/Storage/IStorageItem.cs +++ b/src/Avalonia.Base/Platform/Storage/IStorageItem.cs @@ -44,7 +44,7 @@ public interface IStorageItem : IDisposable /// /// Returns identifier of a bookmark. Can be null if OS denied request. /// - Task SaveBookmark(); + Task SaveBookmarkAsync(); /// /// Gets the parent folder of the current storage item. diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs b/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs index 80e64118ee..889c1d34c8 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Server; -namespace Avalonia.Rendering.Composition.Animations; +// Special license applies License.md +namespace Avalonia.Rendering.Composition.Animations; /// /// The base class for both key-frame and expression animation instances @@ -79,4 +80,4 @@ internal abstract class AnimationInstanceBase : IAnimationInstance _invalidated = true; TargetObject.NotifyAnimatedValueChanged(Property); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs index c5102a2d7d..a6db4330a3 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs @@ -1,12 +1,11 @@ // ReSharper disable InconsistentNaming // ReSharper disable CheckNamespace -using System; -using System.Collections.Generic; using System.Numerics; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Server; -using Avalonia.Rendering.Composition.Transport; + +// Special license applies License.md namespace Avalonia.Rendering.Composition.Animations { @@ -14,10 +13,10 @@ namespace Avalonia.Rendering.Composition.Animations /// This is the base class for ExpressionAnimation and KeyFrameAnimation. /// /// - /// Use the method to start the animation. + /// Use the method to start the animation. /// Value parameters (as opposed to reference parameters which are set using ) /// are copied and "embedded" into an expression at the time CompositionObject.StartAnimation is called. - /// Changing the value of the variable after is called will not affect + /// Changing the value of the variable after is called will not affect /// the value of the ExpressionAnimation. /// See the remarks section of ExpressionAnimation for additional information. /// @@ -72,4 +71,4 @@ namespace Avalonia.Rendering.Composition.Animations } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs index 89f8ba411d..bad3991f43 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using Avalonia.Rendering.Composition.Transport; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { public class CompositionAnimationGroup : CompositionObject, ICompositionAnimationBase @@ -21,4 +23,4 @@ namespace Avalonia.Rendering.Composition.Animations { } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs index 163f4e99ba..ec2972044e 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs @@ -3,6 +3,8 @@ using System; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { /// @@ -14,7 +16,7 @@ namespace Avalonia.Rendering.Composition.Animations /// This contrasts s, which use an interpolator to define how the animating /// property changes over time. The mathematical equation can be defined using references to properties /// of Composition objects, mathematical functions and operators and Input. - /// Use the method to start the animation. + /// Use the method to start the animation. /// public class ExpressionAnimation : CompositionAnimation { @@ -50,4 +52,4 @@ namespace Avalonia.Rendering.Composition.Animations => new ExpressionAnimationInstance(ParsedExpression, targetObject, finalValue, CreateSnapshot()); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs index 764bac9931..6c7c556456 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { @@ -46,4 +48,4 @@ namespace Avalonia.Rendering.Composition.Animations _finalValue = finalValue; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs index 4e1972f2c6..8ec4ec19bc 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs @@ -2,6 +2,8 @@ using System; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { internal interface IAnimationInstance @@ -13,4 +15,4 @@ namespace Avalonia.Rendering.Composition.Animations void Deactivate(); void Invalidate(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs index 87e5ad757a..91b37a81af 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs @@ -2,6 +2,8 @@ using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { /// @@ -12,4 +14,4 @@ namespace Avalonia.Rendering.Composition.Animations internal void InternalOnly(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs index f4bcc6ff38..72be4edd07 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Avalonia.Rendering.Composition.Transport; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { /// @@ -79,4 +81,4 @@ namespace Avalonia.Rendering.Composition.Animations return rv; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs b/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs index a4eeacef32..e19c0ff098 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs @@ -1,6 +1,8 @@ using System; using System.Numerics; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { /// @@ -73,4 +75,4 @@ namespace Avalonia.Rendering.Composition.Animations public static BooleanInterpolator Instance { get; } = new BooleanInterpolator(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs index 49b3ab753a..d21a4d06e3 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs @@ -2,6 +2,8 @@ using System; using Avalonia.Animation; using Avalonia.Animation.Easings; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { @@ -22,9 +24,9 @@ namespace Avalonia.Rendering.Composition.Animations /// The delay behavior of the key frame animation. /// public AnimationDelayBehavior DelayBehavior { get; set; } - + /// - /// Delay before the animation starts after is called. + /// Delay before the animation starts after is called. /// public System.TimeSpan DelayTime { get; set; } @@ -131,4 +133,4 @@ namespace Avalonia.Rendering.Composition.Animations /// SetToFinalValue } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs index 0c0fcfaf2b..e20a4a9ad8 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs @@ -4,6 +4,8 @@ using Avalonia.Animation; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { /// @@ -175,4 +177,4 @@ namespace Avalonia.Rendering.Composition.Animations base.Deactivate(); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs index 369cc80b95..79045ccff8 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using Avalonia.Animation.Easings; using Avalonia.Rendering.Composition.Expressions; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { @@ -86,4 +88,4 @@ namespace Avalonia.Rendering.Composition.Animations { public void InsertExpressionKeyFrame(float normalizedProgressKey, string value, IEasing easingFunction); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs b/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs index fc6cfc9f3d..af3c344999 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using Avalonia.Rendering.Composition.Expressions; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Animations { /// @@ -46,4 +48,4 @@ namespace Avalonia.Rendering.Composition.Animations public ExpressionVariant GetProperty(string name) => GetParameter(name); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index a571a0518b..9aa3c25425 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -11,6 +11,8 @@ using Avalonia.Rendering.Composition.Server; using Avalonia.Threading; using Avalonia.VisualTree; +// Special license applies License.md + namespace Avalonia.Rendering.Composition; /// @@ -69,7 +71,7 @@ public class CompositingRenderer : IRendererWithCompositor if(_queuedUpdate) return; _queuedUpdate = true; - Dispatcher.UIThread.Post(_update, DispatcherPriority.Composition); + _compositor.InvokeWhenReadyForNextCommit(_update); } /// diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs index 49aea1c3dc..77b392eee5 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs @@ -5,6 +5,8 @@ using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Transport; using Avalonia.VisualTree; +// Special license applies License.md + namespace Avalonia.Rendering.Composition; @@ -72,4 +74,4 @@ internal class CompositionDrawListVisual : CompositionContainerVisual return true; return false; } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs b/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs index f529ee9cff..50332926ad 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs @@ -5,6 +5,8 @@ using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Transport; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -138,4 +140,4 @@ namespace Avalonia.Rendering.Composition writer.Write((byte)(IsDisposed ? 1 : 0)); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs b/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs index ee4552d154..7d794af9a2 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs @@ -5,6 +5,8 @@ using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Transport; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -144,4 +146,4 @@ namespace Avalonia.Rendering.Composition TypeMismatch, NotFound } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs index 01b2d0d5d9..4e53e163ec 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs @@ -4,6 +4,8 @@ using System.Numerics; using Avalonia.Collections.Pooled; using Avalonia.VisualTree; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -127,4 +129,4 @@ namespace Avalonia.Rendering.Composition Compositor.Server.Render(); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Compositor.cs b/src/Avalonia.Base/Rendering/Composition/Compositor.cs index 1bdae44cb9..10360f7874 100644 --- a/src/Avalonia.Base/Rendering/Composition/Compositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Compositor.cs @@ -12,6 +12,8 @@ using Avalonia.Rendering.Composition.Transport; using Avalonia.Threading; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -31,6 +33,7 @@ namespace Avalonia.Rendering.Composition internal IEasing DefaultEasing { get; } private List? _invokeOnNextCommit; private readonly Stack> _invokeListPool = new(); + private Task? _lastBatchCompleted; /// /// Creates a new compositor on a specified render loop that would use a particular GPU @@ -84,7 +87,7 @@ namespace Avalonia.Rendering.Composition if (_invokeOnNextCommit != null) ScheduleCommitCallbacks(batch.Completed); - return batch.Completed; + return _lastBatchCompleted = batch.Completed; } async void ScheduleCommitCallbacks(Task task) @@ -137,5 +140,15 @@ namespace Avalonia.Rendering.Composition _invokeOnNextCommit ??= _invokeListPool.Count > 0 ? _invokeListPool.Pop() : new(); _invokeOnNextCommit.Add(action); } + + public void InvokeWhenReadyForNextCommit(Action action) + { + if (_lastBatchCompleted == null || _lastBatchCompleted.IsCompleted) + Dispatcher.UIThread.Post(action, DispatcherPriority.Composition); + else + _lastBatchCompleted.ContinueWith( + static (_, state) => Dispatcher.UIThread.Post((Action)state!, DispatcherPriority.Composition), + action); + } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs index caf074dd6b..9b9c44b95f 100644 --- a/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs @@ -1,5 +1,7 @@ using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -21,4 +23,4 @@ namespace Avalonia.Rendering.Composition base.OnRootChangedCore(); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs index 432a0832f2..10a7c3e360 100644 --- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs +++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs @@ -4,6 +4,8 @@ using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Drawing; /// @@ -99,4 +101,4 @@ internal class CompositionDrawListBuilder if (count < Count) _operations!.RemoveRange(count, _operations.Count - count); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs index d7c1ef125d..01216d19ed 100644 --- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs +++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs @@ -8,6 +8,9 @@ using Avalonia.Rendering.Composition.Drawing; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; using Avalonia.VisualTree; + +// Special license applies License.md + namespace Avalonia.Rendering.Composition; /// @@ -388,4 +391,4 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW } return null; } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs b/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs index 1397a20fb6..5bd8e4a4d3 100644 --- a/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs +++ b/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs @@ -1,3 +1,5 @@ +// Special license applies License.md + namespace Avalonia.Rendering.Composition; /// @@ -11,4 +13,4 @@ public static class ElementComposition /// /// public static CompositionVisual? GetElementVisual(Visual visual) => visual.CompositionVisual; -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Enums.cs b/src/Avalonia.Base/Rendering/Composition/Enums.cs index e349845cbf..cc37b25701 100644 --- a/src/Avalonia.Base/Rendering/Composition/Enums.cs +++ b/src/Avalonia.Base/Rendering/Composition/Enums.cs @@ -1,5 +1,7 @@ using System; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { public enum CompositionBlendMode @@ -117,4 +119,4 @@ namespace Avalonia.Rendering.Composition Fill = 1, //TODO: Uniform, UniformToFill } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs index 44347d2c7a..896ae4fc3a 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs @@ -4,6 +4,8 @@ using System.Numerics; using Avalonia.Rendering.Composition.Animations; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { /// @@ -234,4 +236,4 @@ namespace Avalonia.Rendering.Composition.Expressions public static BuiltInExpressionFfi Instance { get; } = new BuiltInExpressionFfi(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs index 85c6141409..c15487065c 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Numerics; using Avalonia.Media; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { /// @@ -181,4 +183,4 @@ namespace Avalonia.Rendering.Composition.Expressions ); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs index 5abba00365..ff2069e71e 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs @@ -4,6 +4,8 @@ using System.Globalization; using System.Reflection; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { /// @@ -374,4 +376,4 @@ namespace Avalonia.Rendering.Composition.Expressions -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs index 9d23551e43..9086c59aad 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { internal struct ExpressionEvaluationContext @@ -29,4 +31,4 @@ namespace Avalonia.Rendering.Composition.Expressions { bool Call(string name, IReadOnlyList arguments, out ExpressionVariant result); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParseException.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParseException.cs index 6a207a3bf7..c32a7832a6 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParseException.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParseException.cs @@ -1,5 +1,7 @@ using System; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { internal class ExpressionParseException : Exception @@ -11,4 +13,4 @@ namespace Avalonia.Rendering.Composition.Expressions Position = position; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParser.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParser.cs index 5924bb8f1b..3937d48187 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParser.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParser.cs @@ -5,6 +5,8 @@ using System.Linq; // ReSharper disable StringLiteralTypo +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { internal class ExpressionParser @@ -295,4 +297,4 @@ namespace Avalonia.Rendering.Composition.Expressions } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionTrackedValues.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionTrackedValues.cs index 334f975aa0..e386e058df 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionTrackedValues.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionTrackedValues.cs @@ -2,6 +2,8 @@ using System.Collections; using System.Collections.Generic; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions; internal class ExpressionTrackedObjects : IEnumerable @@ -54,4 +56,4 @@ internal class ExpressionTrackedObjects : IEnumerable _stack.Push(obj); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs index 7b900534d8..6e53a138cd 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs @@ -4,6 +4,8 @@ using System.Numerics; using System.Runtime.InteropServices; using Avalonia.Media; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { internal enum VariantType @@ -727,4 +729,4 @@ namespace Avalonia.Rendering.Composition.Expressions } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs index 27782c8c2c..bb7372c375 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs @@ -1,6 +1,8 @@ using System; using System.Globalization; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Expressions { /// @@ -256,4 +258,4 @@ namespace Avalonia.Rendering.Composition.Expressions public override string ToString() => _s.ToString(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs b/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs index 045a4f8cc6..131a51b5e6 100644 --- a/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs +++ b/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs @@ -1,6 +1,8 @@ +// Special license applies License.md + namespace Avalonia.Rendering.Composition; internal interface ICompositionTargetDebugEvents { void RectInvalidated(Rect rc); -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/License.md b/src/Avalonia.Base/Rendering/Composition/License.md new file mode 100644 index 0000000000..d1b709859e --- /dev/null +++ b/src/Avalonia.Base/Rendering/Composition/License.md @@ -0,0 +1,7 @@ +Please note: Any code in this directory is excluded from the normal MIT license. + +This code is owned and copyright to Avalonia OU. + +This code may be used free of charge by any application that consumes Avalonia binary packages as a direct or indirect dependency. + +Explicit permission is required for any other use outside of Avalonia applications. \ No newline at end of file diff --git a/src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs b/src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs index 2cb500cae4..3d8d5bae78 100644 --- a/src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs +++ b/src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs @@ -1,5 +1,7 @@ using System.Numerics; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { static class MatrixUtils @@ -63,4 +65,4 @@ namespace Avalonia.Rendering.Composition matrix44.M42, matrix44.M44); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs b/src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs index 282c0e113d..5d63c8a4b3 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Threading; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server; internal class CompositionProperty @@ -12,4 +14,4 @@ internal class CompositionProperty { Id = Interlocked.Increment(ref s_NextId) }; -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs index e261507f60..7eb35a68ed 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs @@ -6,6 +6,8 @@ using Avalonia.Rendering.Composition.Drawing; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server; /// @@ -176,4 +178,4 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl, IDrawingCont if (_impl is IDrawingContextWithAcrylicLikeSupport acrylic) acrylic.DrawRectangle(material, rect); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs b/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs index 7585710540..b0b3982ed5 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs @@ -6,6 +6,8 @@ using Avalonia.Media.TextFormatting; using Avalonia.Platform; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server; /// @@ -73,4 +75,4 @@ internal class FpsCounter offset += run.Size.Width; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs b/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs index c9592b70ab..d9df176e66 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs @@ -1,3 +1,5 @@ +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -43,4 +45,4 @@ namespace Avalonia.Rendering.Composition.Server } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs index f7152293cc..19349a5196 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs @@ -1,6 +1,8 @@ using System.Numerics; using Avalonia.Platform; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -41,4 +43,4 @@ namespace Avalonia.Rendering.Composition.Server Children = new ServerCompositionVisualCollection(Compositor); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs index 93a5226f83..6cbd2797f9 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs @@ -7,6 +7,8 @@ using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server; /// @@ -72,4 +74,4 @@ internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisua return UiVisual.GetType().ToString(); } #endif -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionSurface.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionSurface.cs index 462a193a86..32a99fa187 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionSurface.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionSurface.cs @@ -1,3 +1,5 @@ +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { internal abstract class ServerCompositionSurface : ServerObject @@ -6,4 +8,4 @@ namespace Avalonia.Rendering.Composition.Server { } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs index 882b66bf70..c20594aaca 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs @@ -9,6 +9,8 @@ using Avalonia.Platform; using Avalonia.Rendering.Composition.Transport; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -218,4 +220,4 @@ namespace Avalonia.Rendering.Composition.Server public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs index c5af74e2dd..405c7879b7 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs @@ -1,3 +1,5 @@ +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server; partial class ServerCompositionVisual @@ -73,4 +75,4 @@ partial class ServerCompositionVisual || offset == s_IdOfSizeProperty) _clipSizeDirty = true; } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs index c0e487f209..b742f1d44a 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs @@ -6,6 +6,8 @@ using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Transport; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -234,4 +236,4 @@ namespace Avalonia.Rendering.Composition.Server } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs index 564f792ebe..bfc2b2d626 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs @@ -6,6 +6,8 @@ using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Transport; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -106,6 +108,7 @@ namespace Avalonia.Rendering.Composition.Server private void RenderCore() { ApplyPendingBatches(); + CompletePendingBatches(); foreach(var animation in _activeAnimations) _animationsToUpdate.Add(animation); @@ -117,8 +120,6 @@ namespace Avalonia.Rendering.Composition.Server foreach (var t in _activeTargets) t.Render(); - - CompletePendingBatches(); } public void AddCompositionTarget(ServerCompositionTarget target) @@ -137,4 +138,4 @@ namespace Avalonia.Rendering.Composition.Server public void RemoveFromClock(IAnimationInstance animationInstance) => _activeAnimations.Remove(animationInstance); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs index 39d6a8dc70..08a3fdce22 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using Avalonia.Rendering.Composition.Transport; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -41,4 +43,4 @@ namespace Avalonia.Rendering.Composition.Server { } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs index 93ea8e8dee..257d3b29a2 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs @@ -7,6 +7,8 @@ using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Transport; using Avalonia.Utilities; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Server { /// @@ -177,4 +179,4 @@ namespace Avalonia.Rendering.Composition.Server ItselfLastChangedBy = batch.SequenceId; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs b/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs index e69768d3bf..0cf1650ccf 100644 --- a/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs +++ b/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Transport { /// @@ -36,4 +38,4 @@ namespace Avalonia.Rendering.Composition.Transport public Task Completed => _tcs.Task; } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs index 6db480a966..8b68900994 100644 --- a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs +++ b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs @@ -5,6 +5,8 @@ using System.Runtime.CompilerServices; using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Transport; /// diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamArrayPool.cs b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamArrayPool.cs index b0a89c6f92..f24f449551 100644 --- a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamArrayPool.cs +++ b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamArrayPool.cs @@ -5,6 +5,8 @@ using System.Runtime.InteropServices; using Avalonia.Platform; using Avalonia.Threading; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Transport; /// @@ -153,4 +155,4 @@ internal sealed class BatchStreamMemoryPool : BatchStreamPoolBase protected override IntPtr CreateItem() => Marshal.AllocHGlobal(BufferSize); protected override void DestroyItem(IntPtr item) => Marshal.FreeHGlobal(item); -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamDebugMarker.cs b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamDebugMarker.cs index 7d21b03f24..fed0f4d4aa 100644 --- a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamDebugMarker.cs +++ b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamDebugMarker.cs @@ -1,9 +1,11 @@ using System; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Transport; internal class BatchStreamDebugMarkers { public static object ObjectEndMarker = new object(); public static Guid ObjectEndMagic = Guid.NewGuid(); -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs b/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs index e295c3c2c8..603c7582a1 100644 --- a/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs +++ b/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs @@ -2,6 +2,8 @@ using System.Collections; using System.Collections.Generic; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition.Transport { /// @@ -95,4 +97,4 @@ namespace Avalonia.Rendering.Composition.Transport _changed = false; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Visual.cs b/src/Avalonia.Base/Rendering/Composition/Visual.cs index 7ebbb0aa96..7356b7b9e8 100644 --- a/src/Avalonia.Base/Rendering/Composition/Visual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Visual.cs @@ -3,6 +3,8 @@ using System.Numerics; using Avalonia.Media; using Avalonia.VisualTree; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -53,4 +55,4 @@ namespace Avalonia.Rendering.Composition internal virtual bool HitTest(Point point, Func? filter) => true; } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs b/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs index 60ebd9271c..6981dc39e3 100644 --- a/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs +++ b/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs @@ -1,6 +1,8 @@ using System; using Avalonia.Rendering.Composition.Server; +// Special license applies License.md + namespace Avalonia.Rendering.Composition { /// @@ -70,4 +72,4 @@ namespace Avalonia.Rendering.Composition item.Parent = item; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/readme.md b/src/Avalonia.Base/Rendering/Composition/readme.md new file mode 100644 index 0000000000..6c238db191 --- /dev/null +++ b/src/Avalonia.Base/Rendering/Composition/readme.md @@ -0,0 +1,3 @@ +Please note the composition renderer is not subject to the usual MIT license. + +Please contact us for more details and see [License.md](https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md) diff --git a/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs index 59ebcf5109..12b67105e9 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs @@ -83,7 +83,7 @@ namespace Avalonia.Rendering.SceneGraph if (Material != null) { var rect = Rect.Rect; - return rect.Contains(p); + return rect.ContainsExclusive(p); } } diff --git a/src/Avalonia.Base/Rendering/SceneGraph/GeometryNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/GeometryNode.cs index 4b43f93aee..cf53b86fa7 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/GeometryNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/GeometryNode.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using Avalonia.Media; using Avalonia.Media.Immutable; using Avalonia.Platform; -using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { @@ -19,7 +17,7 @@ namespace Avalonia.Rendering.SceneGraph /// The fill brush. /// The stroke pen. /// The geometry. - /// Child scenes for drawing visual brushes. + /// Auxiliary data required to draw the brush. public GeometryNode(Matrix transform, IBrush? brush, IPen? pen, diff --git a/src/Avalonia.Base/Rendering/SceneGraph/GlyphRunNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/GlyphRunNode.cs index 9199611ed6..1d85e95835 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/GlyphRunNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/GlyphRunNode.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; - using Avalonia.Media; -using Avalonia.Media.Immutable; using Avalonia.Platform; -using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { @@ -19,7 +15,7 @@ namespace Avalonia.Rendering.SceneGraph /// The transform. /// The foreground brush. /// The glyph run to draw. - /// Child scenes for drawing visual brushes. + /// Auxiliary data required to draw the brush. public GlyphRunNode( Matrix transform, IBrush foreground, @@ -73,6 +69,6 @@ namespace Avalonia.Rendering.SceneGraph } /// - public override bool HitTest(Point p) => Bounds.Contains(p); + public override bool HitTest(Point p) => Bounds.ContainsExclusive(p); } } diff --git a/src/Avalonia.Base/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/ImageNode.cs index 23267166a5..339881e675 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/ImageNode.cs @@ -109,7 +109,7 @@ namespace Avalonia.Rendering.SceneGraph } /// - public override bool HitTest(Point p) => Bounds.Contains(p); + public override bool HitTest(Point p) => Bounds.ContainsExclusive(p); public override void Dispose() { diff --git a/src/Avalonia.Base/Rendering/SceneGraph/LineNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/LineNode.cs index ee5ec0a5fc..0af8ba2752 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/LineNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/LineNode.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using Avalonia.Media; using Avalonia.Media.Immutable; using Avalonia.Platform; -using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { @@ -19,7 +17,7 @@ namespace Avalonia.Rendering.SceneGraph /// The stroke pen. /// The start point of the line. /// The end point of the line. - /// Child scenes for drawing visual brushes. + /// Auxiliary data required to draw the brush. public LineNode( Matrix transform, IPen pen, diff --git a/src/Avalonia.Base/Rendering/SceneGraph/OpacityMaskNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/OpacityMaskNode.cs index 549c1fd7de..5fd200ddff 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/OpacityMaskNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/OpacityMaskNode.cs @@ -17,7 +17,7 @@ namespace Avalonia.Rendering.SceneGraph /// /// The opacity mask to push. /// The bounds of the mask. - /// Child scenes for drawing visual brushes. + /// Auxiliary data required to draw the brush. public OpacityMaskNode(IBrush mask, Rect bounds, IDisposable? aux = null) : base(Rect.Empty, Matrix.Identity, aux) { diff --git a/src/Avalonia.Base/Rendering/SceneGraph/RectangleNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/RectangleNode.cs index 7b79c446f9..f2ffd7411c 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/RectangleNode.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/RectangleNode.cs @@ -20,7 +20,7 @@ namespace Avalonia.Rendering.SceneGraph /// The stroke pen. /// The rectangle to draw. /// The box shadow parameters - /// Child scenes for drawing visual brushes. + /// Auxiliary data required to draw the brush. public RectangleNode( Matrix transform, IBrush? brush, @@ -103,13 +103,13 @@ namespace Avalonia.Rendering.SceneGraph if (Brush != null) { var rect = Rect.Rect.Inflate((Pen?.Thickness / 2) ?? 0); - return rect.Contains(p); + return rect.ContainsExclusive(p); } else { var borderRect = Rect.Rect.Inflate((Pen?.Thickness / 2) ?? 0); var emptyRect = Rect.Rect.Deflate((Pen?.Thickness / 2) ?? 0); - return borderRect.Contains(p) && !emptyRect.Contains(p); + return borderRect.ContainsExclusive(p) && !emptyRect.ContainsExclusive(p); } } diff --git a/src/Avalonia.Base/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Base/Rendering/SceneGraph/Scene.cs index 20c23d7bee..c436299018 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/Scene.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/Scene.cs @@ -300,7 +300,7 @@ namespace Avalonia.Rendering.SceneGraph if (node.ClipToBounds) { clip = clip == null ? node.ClipBounds : clip.Value.Intersect(node.ClipBounds); - clipped = !clip.Value.Contains(_point); + clipped = !clip.Value.ContainsExclusive(_point); } if (node.GeometryClip != null) diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs index 3d5be806e1..d381979c1e 100644 --- a/src/Avalonia.Base/Utilities/MathUtilities.cs +++ b/src/Avalonia.Base/Utilities/MathUtilities.cs @@ -255,7 +255,7 @@ namespace Avalonia.Utilities /// /// Clamps a value between a minimum and maximum value. /// - /// The value. + /// The value. /// The minimum value. /// The maximum value. /// The clamped value. diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs index 39a83c00c4..5915388822 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs +++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs @@ -326,8 +326,8 @@ namespace Avalonia.Build.Tasks var op = i[c].Operand as MethodReference; // TODO: Throw an error - // This usually happens when same XAML resource was added twice for some weird reason - // We currently support it for dual-named default theme resource + // This usually happens when the same XAML resource was added twice for some weird reason + // We currently support it for dual-named default theme resources if (op != null && op.Name == TrampolineName) { diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorSlider.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorSlider.xaml deleted file mode 100644 index 35cd7a9faa..0000000000 --- a/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorSlider.xaml +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml deleted file mode 100644 index ebecd65cc3..0000000000 --- a/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml index a4d5ff673f..74a1df4991 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml @@ -1,14 +1,10 @@ - + - - - 5,5,0,0 - - - @@ -46,7 +42,7 @@ - + + SelectedIndex="{Binding SelectedIndex, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"> + + + 5,5,0,0 + + - - - - - + - + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml index 74f33d1258..1c4a44d081 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml @@ -1,15 +1,14 @@ - + - - - 80 - 40 - + + 80 + 40 - + - + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml index 162ac372de..eb67ada334 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml @@ -1,188 +1,190 @@ - + - + - + - + - - + + + + + + - - - - + + - - + - + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml index dba4ad19f5..f95721c881 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml @@ -1,9 +1,10 @@ - + - - - - + + + - - - + + + - - - - - + + + + + - - + + - - - + + + - + + + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml index e25e822f3f..59cc48975f 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml @@ -1,86 +1,87 @@ - + - - - - - - - 48 - 30 - 80 - - - M3 2C3.27614 2 3.5 2.22386 3.5 2.5V5.5C3.5 5.77614 3.72386 6 4 6H16C16.2761 6 16.5 5.77614 - 16.5 5.5V2.5C16.5 2.22386 16.7239 2 17 2C17.2761 2 17.5 2.22386 17.5 2.5V5.5C17.5 6.32843 - 16.8284 7 16 7H15.809L12.2236 14.1708C12.0615 14.4951 11.7914 14.7431 11.4695 - 14.8802C11.4905 15.0808 11.5 15.2891 11.5 15.5C11.5 16.0818 11.4278 16.6623 11.2268 - 17.1165C11.019 17.5862 10.6266 18 10 18C9.37343 18 8.98105 17.5862 8.77323 17.1165C8.57222 - 16.6623 8.5 16.0818 8.5 15.5C8.5 15.2891 8.50952 15.0808 8.53051 14.8802C8.20863 14.7431 - 7.93851 14.4951 7.77639 14.1708L4.19098 7H4C3.17157 7 2.5 6.32843 2.5 5.5V2.5C2.5 2.22386 - 2.72386 2 3 2ZM9.11803 14H10.882C11.0714 14 11.2445 13.893 11.3292 13.7236L14.691 - 7H5.30902L8.67082 13.7236C8.75552 13.893 8.92865 14 9.11803 14ZM9.52346 15C9.50787 15.1549 - 9.5 15.3225 9.5 15.5C9.5 16.0228 9.56841 16.4423 9.6877 16.7119C9.8002 16.9661 9.90782 17 - 10 17C10.0922 17 10.1998 16.9661 10.3123 16.7119C10.4316 16.4423 10.5 16.0228 10.5 - 15.5C10.5 15.3225 10.4921 15.1549 10.4765 15H9.52346Z - - - - M9.75003 6.5C10.1642 6.5 10.5 6.16421 10.5 5.75C10.5 5.33579 10.1642 5 9.75003 5C9.33582 - 5 9.00003 5.33579 9.00003 5.75C9.00003 6.16421 9.33582 6.5 9.75003 6.5ZM12.75 7.5C13.1642 - 7.5 13.5 7.16421 13.5 6.75C13.5 6.33579 13.1642 6 12.75 6C12.3358 6 12 6.33579 12 6.75C12 - 7.16421 12.3358 7.5 12.75 7.5ZM15.25 9C15.25 9.41421 14.9142 9.75 14.5 9.75C14.0858 9.75 - 13.75 9.41421 13.75 9C13.75 8.58579 14.0858 8.25 14.5 8.25C14.9142 8.25 15.25 8.58579 - 15.25 9ZM14.5 12.75C14.9142 12.75 15.25 12.4142 15.25 12C15.25 11.5858 14.9142 11.25 14.5 - 11.25C14.0858 11.25 13.75 11.5858 13.75 12C13.75 12.4142 14.0858 12.75 14.5 12.75ZM13.25 - 14C13.25 14.4142 12.9142 14.75 12.5 14.75C12.0858 14.75 11.75 14.4142 11.75 14C11.75 - 13.5858 12.0858 13.25 12.5 13.25C12.9142 13.25 13.25 13.5858 13.25 14ZM13.6972 - 2.99169C10.9426 1.57663 8.1432 1.7124 5.77007 3.16636C4.55909 3.9083 3.25331 5.46925 - 2.51605 7.05899C2.14542 7.85816 1.89915 8.70492 1.90238 9.49318C1.90566 10.2941 2.16983 - 11.0587 2.84039 11.6053C3.45058 12.1026 3.98165 12.353 4.49574 12.3784C5.01375 12.404 - 5.41804 12.1942 5.73429 12.0076C5.80382 11.9666 5.86891 11.927 5.93113 11.8892C6.17332 - 11.7421 6.37205 11.6214 6.62049 11.5426C6.90191 11.4534 7.2582 11.4205 7.77579 - 11.5787C7.96661 11.637 8.08161 11.7235 8.16212 11.8229C8.24792 11.9289 8.31662 12.0774 - 8.36788 12.2886C8.41955 12.5016 8.44767 12.7527 8.46868 13.0491C8.47651 13.1594 8.48379 - 13.2855 8.49142 13.4176C8.50252 13.6098 8.51437 13.8149 8.52974 14.0037C8.58435 14.6744 - 8.69971 15.4401 9.10362 16.1357C9.51764 16.8488 10.2047 17.439 11.307 17.8158C12.9093 - 18.3636 14.3731 17.9191 15.5126 17.0169C16.6391 16.125 17.4691 14.7761 17.8842 - 13.4272C19.1991 9.15377 17.6728 5.03394 13.6972 2.99169ZM6.29249 4.01905C8.35686 2.75426 - 10.7844 2.61959 13.2403 3.88119C16.7473 5.68275 18.1135 9.28161 16.9284 13.1332C16.5624 - 14.3227 15.8338 15.4871 14.8919 16.2329C13.963 16.9684 12.8486 17.286 11.6305 - 16.8696C10.7269 16.5607 10.2467 16.1129 9.96842 15.6336C9.68001 15.1369 9.57799 14.5556 - 9.52644 13.9225C9.51101 13.733 9.50132 13.5621 9.49147 13.3884C9.48399 13.2564 9.47642 - 13.1229 9.46618 12.9783C9.44424 12.669 9.41175 12.3499 9.33968 12.0529C9.26719 11.7541 - 9.14902 11.4527 8.93935 11.1937C8.72439 10.9282 8.43532 10.7346 8.06801 10.6223C7.36648 - 10.408 6.80266 10.4359 6.31839 10.5893C5.94331 10.7082 5.62016 10.9061 5.37179 - 11.0582C5.31992 11.0899 5.2713 11.1197 5.22616 11.1463C4.94094 11.3146 4.75357 11.39 - 4.54514 11.3796C4.33279 11.3691 4.00262 11.2625 3.47218 10.8301C3.0866 10.5158 2.90473 - 10.0668 2.90237 9.48908C2.89995 8.89865 3.08843 8.20165 3.42324 7.47971C4.09686 6.0272 - 5.28471 4.63649 6.29249 4.01905Z - - - - M14.95 5C14.7184 3.85888 13.7095 3 12.5 3C11.2905 3 10.2816 3.85888 10.05 5H2.5C2.22386 - 5 2 5.22386 2 5.5C2 5.77614 2.22386 6 2.5 6H10.05C10.2816 7.14112 11.2905 8 12.5 8C13.7297 - 8 14.752 7.11217 14.961 5.94254C14.9575 5.96177 14.9539 5.98093 14.95 6H17.5C17.7761 6 18 - 5.77614 18 5.5C18 5.22386 17.7761 5 17.5 5H14.95ZM12.5 7C11.6716 7 11 6.32843 11 5.5C11 - 4.67157 11.6716 4 12.5 4C13.3284 4 14 4.67157 14 5.5C14 6.32843 13.3284 7 12.5 7ZM9.94999 - 14C9.71836 12.8589 8.70948 12 7.5 12C6.29052 12 5.28164 12.8589 5.05001 14H2.5C2.22386 - 14 2 14.2239 2 14.5C2 14.7761 2.22386 15 2.5 15H5.05001C5.28164 16.1411 6.29052 17 7.5 - 17C8.70948 17 9.71836 16.1411 9.94999 15H17.5C17.7761 15 18 14.7761 18 14.5C18 14.2239 - 17.7761 14 17.5 14H9.94999ZM7.5 16C6.67157 16 6 15.3284 6 14.5C6 13.6716 6.67157 13 7.5 - 13C8.32843 13 9 13.6716 9 14.5C9 15.3284 8.32843 16 7.5 16Z - - + + + + + + 48 + 30 + 80 + + + M3 2C3.27614 2 3.5 2.22386 3.5 2.5V5.5C3.5 5.77614 3.72386 6 4 6H16C16.2761 6 16.5 5.77614 + 16.5 5.5V2.5C16.5 2.22386 16.7239 2 17 2C17.2761 2 17.5 2.22386 17.5 2.5V5.5C17.5 6.32843 + 16.8284 7 16 7H15.809L12.2236 14.1708C12.0615 14.4951 11.7914 14.7431 11.4695 + 14.8802C11.4905 15.0808 11.5 15.2891 11.5 15.5C11.5 16.0818 11.4278 16.6623 11.2268 + 17.1165C11.019 17.5862 10.6266 18 10 18C9.37343 18 8.98105 17.5862 8.77323 17.1165C8.57222 + 16.6623 8.5 16.0818 8.5 15.5C8.5 15.2891 8.50952 15.0808 8.53051 14.8802C8.20863 14.7431 + 7.93851 14.4951 7.77639 14.1708L4.19098 7H4C3.17157 7 2.5 6.32843 2.5 5.5V2.5C2.5 2.22386 + 2.72386 2 3 2ZM9.11803 14H10.882C11.0714 14 11.2445 13.893 11.3292 13.7236L14.691 + 7H5.30902L8.67082 13.7236C8.75552 13.893 8.92865 14 9.11803 14ZM9.52346 15C9.50787 15.1549 + 9.5 15.3225 9.5 15.5C9.5 16.0228 9.56841 16.4423 9.6877 16.7119C9.8002 16.9661 9.90782 17 + 10 17C10.0922 17 10.1998 16.9661 10.3123 16.7119C10.4316 16.4423 10.5 16.0228 10.5 + 15.5C10.5 15.3225 10.4921 15.1549 10.4765 15H9.52346Z + + + + M9.75003 6.5C10.1642 6.5 10.5 6.16421 10.5 5.75C10.5 5.33579 10.1642 5 9.75003 5C9.33582 + 5 9.00003 5.33579 9.00003 5.75C9.00003 6.16421 9.33582 6.5 9.75003 6.5ZM12.75 7.5C13.1642 + 7.5 13.5 7.16421 13.5 6.75C13.5 6.33579 13.1642 6 12.75 6C12.3358 6 12 6.33579 12 6.75C12 + 7.16421 12.3358 7.5 12.75 7.5ZM15.25 9C15.25 9.41421 14.9142 9.75 14.5 9.75C14.0858 9.75 + 13.75 9.41421 13.75 9C13.75 8.58579 14.0858 8.25 14.5 8.25C14.9142 8.25 15.25 8.58579 + 15.25 9ZM14.5 12.75C14.9142 12.75 15.25 12.4142 15.25 12C15.25 11.5858 14.9142 11.25 14.5 + 11.25C14.0858 11.25 13.75 11.5858 13.75 12C13.75 12.4142 14.0858 12.75 14.5 12.75ZM13.25 + 14C13.25 14.4142 12.9142 14.75 12.5 14.75C12.0858 14.75 11.75 14.4142 11.75 14C11.75 + 13.5858 12.0858 13.25 12.5 13.25C12.9142 13.25 13.25 13.5858 13.25 14ZM13.6972 + 2.99169C10.9426 1.57663 8.1432 1.7124 5.77007 3.16636C4.55909 3.9083 3.25331 5.46925 + 2.51605 7.05899C2.14542 7.85816 1.89915 8.70492 1.90238 9.49318C1.90566 10.2941 2.16983 + 11.0587 2.84039 11.6053C3.45058 12.1026 3.98165 12.353 4.49574 12.3784C5.01375 12.404 + 5.41804 12.1942 5.73429 12.0076C5.80382 11.9666 5.86891 11.927 5.93113 11.8892C6.17332 + 11.7421 6.37205 11.6214 6.62049 11.5426C6.90191 11.4534 7.2582 11.4205 7.77579 + 11.5787C7.96661 11.637 8.08161 11.7235 8.16212 11.8229C8.24792 11.9289 8.31662 12.0774 + 8.36788 12.2886C8.41955 12.5016 8.44767 12.7527 8.46868 13.0491C8.47651 13.1594 8.48379 + 13.2855 8.49142 13.4176C8.50252 13.6098 8.51437 13.8149 8.52974 14.0037C8.58435 14.6744 + 8.69971 15.4401 9.10362 16.1357C9.51764 16.8488 10.2047 17.439 11.307 17.8158C12.9093 + 18.3636 14.3731 17.9191 15.5126 17.0169C16.6391 16.125 17.4691 14.7761 17.8842 + 13.4272C19.1991 9.15377 17.6728 5.03394 13.6972 2.99169ZM6.29249 4.01905C8.35686 2.75426 + 10.7844 2.61959 13.2403 3.88119C16.7473 5.68275 18.1135 9.28161 16.9284 13.1332C16.5624 + 14.3227 15.8338 15.4871 14.8919 16.2329C13.963 16.9684 12.8486 17.286 11.6305 + 16.8696C10.7269 16.5607 10.2467 16.1129 9.96842 15.6336C9.68001 15.1369 9.57799 14.5556 + 9.52644 13.9225C9.51101 13.733 9.50132 13.5621 9.49147 13.3884C9.48399 13.2564 9.47642 + 13.1229 9.46618 12.9783C9.44424 12.669 9.41175 12.3499 9.33968 12.0529C9.26719 11.7541 + 9.14902 11.4527 8.93935 11.1937C8.72439 10.9282 8.43532 10.7346 8.06801 10.6223C7.36648 + 10.408 6.80266 10.4359 6.31839 10.5893C5.94331 10.7082 5.62016 10.9061 5.37179 + 11.0582C5.31992 11.0899 5.2713 11.1197 5.22616 11.1463C4.94094 11.3146 4.75357 11.39 + 4.54514 11.3796C4.33279 11.3691 4.00262 11.2625 3.47218 10.8301C3.0866 10.5158 2.90473 + 10.0668 2.90237 9.48908C2.89995 8.89865 3.08843 8.20165 3.42324 7.47971C4.09686 6.0272 + 5.28471 4.63649 6.29249 4.01905Z + + + + M14.95 5C14.7184 3.85888 13.7095 3 12.5 3C11.2905 3 10.2816 3.85888 10.05 5H2.5C2.22386 + 5 2 5.22386 2 5.5C2 5.77614 2.22386 6 2.5 6H10.05C10.2816 7.14112 11.2905 8 12.5 8C13.7297 + 8 14.752 7.11217 14.961 5.94254C14.9575 5.96177 14.9539 5.98093 14.95 6H17.5C17.7761 6 18 + 5.77614 18 5.5C18 5.22386 17.7761 5 17.5 5H14.95ZM12.5 7C11.6716 7 11 6.32843 11 5.5C11 + 4.67157 11.6716 4 12.5 4C13.3284 4 14 4.67157 14 5.5C14 6.32843 13.3284 7 12.5 7ZM9.94999 + 14C9.71836 12.8589 8.70948 12 7.5 12C6.29052 12 5.28164 12.8589 5.05001 14H2.5C2.22386 + 14 2 14.2239 2 14.5C2 14.7761 2.22386 15 2.5 15H5.05001C5.28164 16.1411 6.29052 17 7.5 + 17C8.70948 17 9.71836 16.1411 9.94999 15H17.5C17.7761 15 18 14.7761 18 14.5C18 14.2239 + 17.7761 14 17.5 14H9.94999ZM7.5 16C6.67157 16 6 15.3284 6 14.5C6 13.6716 6.67157 13 7.5 + 13C8.32843 13 9 13.6716 9 14.5C9 15.3284 8.32843 16 7.5 16Z + + + 3 - + - + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml index 186b6de9bc..a5a94a2322 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml @@ -3,42 +3,48 @@ xmlns:converters="using:Avalonia.Controls.Converters"> - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + - - - + + + + + + + + + + + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorPreviewer.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorPreviewer.xaml similarity index 89% rename from src/Avalonia.Controls.ColorPicker/Themes/Default/ColorPreviewer.xaml rename to src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorPreviewer.xaml index c3bc7df4a4..e067fe4ab5 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorPreviewer.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorPreviewer.xaml @@ -1,15 +1,14 @@ - + - - - 80 - 40 - + + 80 + 40 - + - + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorSlider.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorSlider.xaml new file mode 100644 index 0000000000..9aa2dcd9f9 --- /dev/null +++ b/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorSlider.xaml @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorSpectrum.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorSpectrum.xaml similarity index 69% rename from src/Avalonia.Controls.ColorPicker/Themes/Default/ColorSpectrum.xaml rename to src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorSpectrum.xaml index 0e57f6b483..0e137c89c6 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Default/ColorSpectrum.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorSpectrum.xaml @@ -1,9 +1,10 @@ - + - - - - + + + - - - + + + - - - - - + + + + + - + - - - + + + - + + + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml new file mode 100644 index 0000000000..1e507a91fe --- /dev/null +++ b/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Controls.DataGrid/DataGridCell.cs b/src/Avalonia.Controls.DataGrid/DataGridCell.cs index f9685b3682..dd802678d4 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCell.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCell.cs @@ -14,7 +14,7 @@ namespace Avalonia.Controls /// Represents an individual cell. /// [TemplatePart(DATAGRIDCELL_elementRightGridLine, typeof(Rectangle))] - [PseudoClasses(":selected", ":current", ":edited", ":invalid")] + [PseudoClasses(":selected", ":current", ":edited", ":invalid", ":focus")] public class DataGridCell : ContentControl { private const string DATAGRIDCELL_elementRightGridLine = "PART_RightGridLine"; @@ -216,6 +216,8 @@ namespace Avalonia.Controls PseudoClasses.Set(":edited", IsEdited); PseudoClasses.Set(":invalid", !IsValid); + + PseudoClasses.Set(":focus", OwningGrid.IsFocused && IsCurrent); } // Makes sure the right gridline has the proper stroke and visibility. If lastVisibleColumn is specified, the @@ -245,9 +247,15 @@ namespace Avalonia.Controls if (column == null) { Classes.Clear(); + ClearValue(ThemeProperty); } else { + if (Theme != column.CellTheme) + { + Theme = column.CellTheme; + } + Classes.Replace(column.CellStyleClasses); } } diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs index e57d6bbde2..fbdb979e24 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs @@ -16,6 +16,7 @@ using Avalonia.Controls.Templates; using Avalonia.Controls.Utils; using Avalonia.Layout; using Avalonia.Markup.Xaml.MarkupExtensions; +using Avalonia.Styling; namespace Avalonia.Controls { @@ -36,6 +37,7 @@ namespace Avalonia.Controls private IControl _editingElement; private ICellEditBinding _editBinding; private IBinding _clipboardContentBinding; + private ControlTheme _cellTheme; private readonly Classes _cellStyleClasses = new Classes(); /// @@ -399,6 +401,24 @@ namespace Avalonia.Controls } } } + + /// + /// Backing field for CellTheme property. + /// + public static readonly DirectProperty CellThemeProperty = + AvaloniaProperty.RegisterDirect( + nameof(CellTheme), + o => o.CellTheme, + (o, v) => o.CellTheme = v); + + /// + /// Gets or sets the cell theme. + /// + public ControlTheme CellTheme + { + get { return _cellTheme; } + set { SetAndRaise(CellThemeProperty, ref _cellTheme, value); } + } /// /// Backing field for Header property diff --git a/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs index 9f37e8a6aa..d63c738133 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs @@ -113,7 +113,6 @@ namespace Avalonia.Controls /// public DataGridRowGroupHeader() { - //DefaultStyleKey = typeof(DataGridRowGroupHeader); AddHandler(InputElement.PointerPressedEvent, (s, e) => DataGridRowGroupHeader_PointerPressed(e), handledEventsToo: true); } diff --git a/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs index bb8637cda2..79247aa87f 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs @@ -11,6 +11,7 @@ using System.ComponentModel; using Avalonia.Layout; using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Controls.Documents; +using Avalonia.Styling; namespace Avalonia.Controls { @@ -19,12 +20,20 @@ namespace Avalonia.Controls /// public class DataGridTextColumn : DataGridBoundColumn { + private readonly Lazy _cellTextBoxTheme; + private readonly Lazy _cellTextBlockTheme; + /// /// Initializes a new instance of the class. /// public DataGridTextColumn() { BindingTarget = TextBox.TextProperty; + + _cellTextBoxTheme = new Lazy(() => + OwningGrid.TryFindResource("DataGridCellTextBoxTheme", out var theme) ? (ControlTheme)theme : null); + _cellTextBlockTheme = new Lazy(() => + OwningGrid.TryFindResource("DataGridCellTextBlockTheme", out var theme) ? (ControlTheme)theme : null); } /// @@ -156,16 +165,19 @@ namespace Avalonia.Controls protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem) { var textBox = new TextBox - { - VerticalAlignment = VerticalAlignment.Stretch, - Background = new SolidColorBrush(Colors.Transparent) + { + Name = "CellTextBox" }; + if (_cellTextBoxTheme.Value is { } theme) + { + textBox.Theme = theme; + } SyncProperties(textBox); return textBox; } - + /// /// Gets a read-only element that is bound to the column's property value. /// @@ -174,10 +186,14 @@ namespace Avalonia.Controls /// A new, read-only element that is bound to the column's property value. protected override IControl GenerateElement(DataGridCell cell, object dataItem) { - TextBlock textBlockElement = new TextBlock + var textBlockElement = new TextBlock { Name = "CellTextBlock" }; + if (_cellTextBlockTheme.Value is { } theme) + { + textBlockElement.Theme = theme; + } SyncProperties(textBlockElement); @@ -227,7 +243,7 @@ namespace Avalonia.Controls { if (element == null) { - throw new ArgumentNullException("element"); + throw new ArgumentNullException(nameof(element)); } if (element is AvaloniaObject content) diff --git a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml deleted file mode 100644 index 0d1fe43eb6..0000000000 --- a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml +++ /dev/null @@ -1,305 +0,0 @@ - - - - - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml index fb032fec3e..5ae83427b5 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml @@ -1,8 +1,8 @@ - + 0.6 0.8 - 12,0,12,0 M1875 1011l-787 787v-1798h-128v1798l-787 -787l-90 90l941 941l941 -941z M1965 947l-941 -941l-941 941l90 90l787 -787v1798h128v-1798l787 787z @@ -13,10 +13,12 @@ - + - + @@ -27,14 +29,12 @@ - + - - - - + @@ -44,157 +44,424 @@ Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" /> - + - - + + + + + + + + + + + + + + + - + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fill="{TemplateBinding SeparatorBrush}" + IsVisible="{TemplateBinding AreSeparatorsVisible}" /> - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/src/Avalonia.Controls.DataGrid/Themes/Simple.xaml b/src/Avalonia.Controls.DataGrid/Themes/Simple.xaml new file mode 100644 index 0000000000..6a748f399e --- /dev/null +++ b/src/Avalonia.Controls.DataGrid/Themes/Simple.xaml @@ -0,0 +1,377 @@ + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 6dba33516b..8e5d4e1e06 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Linq; using System.Windows.Input; using Avalonia.Automation.Peers; @@ -281,24 +282,29 @@ namespace Avalonia.Controls /// protected override void OnKeyDown(KeyEventArgs e) { - if (e.Key == Key.Enter) + switch (e.Key) { - OnClick(); - e.Handled = true; - } - else if (e.Key == Key.Space) - { - if (ClickMode == ClickMode.Press) - { + case Key.Enter: OnClick(); + e.Handled = true; + break; + + case Key.Space: + { + if (ClickMode == ClickMode.Press) + { + OnClick(); + } + + IsPressed = true; + e.Handled = true; + break; } - IsPressed = true; - e.Handled = true; - } - else if (e.Key == Key.Escape && Flyout != null) - { - // If Flyout doesn't have focusable content, close the flyout here - Flyout.Hide(); + + case Key.Escape when Flyout != null: + // If Flyout doesn't have focusable content, close the flyout here + CloseFlyout(); + break; } base.OnKeyDown(e); @@ -327,7 +333,14 @@ namespace Avalonia.Controls { if (IsEffectivelyEnabled) { - OpenFlyout(); + if (_isFlyoutOpen) + { + CloseFlyout(); + } + else + { + OpenFlyout(); + } var e = new RoutedEventArgs(ClickEvent); RaiseEvent(e); @@ -348,6 +361,14 @@ namespace Avalonia.Controls Flyout?.ShowAt(this); } + /// + /// Closes the button's flyout. + /// + protected virtual void CloseFlyout() + { + Flyout?.Hide(); + } + /// /// Invoked when the button's flyout is opened. /// @@ -494,8 +515,7 @@ namespace Avalonia.Controls // If flyout is changed while one is already open, make sure we // close the old one first - if (oldFlyout != null && - oldFlyout.IsOpen) + if (oldFlyout != null && oldFlyout.IsOpen) { oldFlyout.Hide(); } diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index 1504d2b25f..00ebcab70e 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -12,17 +12,12 @@ namespace Avalonia.Controls.Primitives { public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider { - static FlyoutBase() - { - Control.ContextFlyoutProperty.Changed.Subscribe(OnContextFlyoutPropertyChanged); - } - /// /// Defines the property /// public static readonly DirectProperty IsOpenProperty = - AvaloniaProperty.RegisterDirect(nameof(IsOpen), - x => x.IsOpen); + AvaloniaProperty.RegisterDirect(nameof(IsOpen), + x => x.IsOpen); /// /// Defines the property @@ -43,6 +38,14 @@ namespace Avalonia.Controls.Primitives AvaloniaProperty.RegisterDirect(nameof(ShowMode), x => x.ShowMode, (x, v) => x.ShowMode = v); + /// + /// Defines the property + /// + public static readonly DirectProperty OverlayInputPassThroughElementProperty = + Popup.OverlayInputPassThroughElementProperty.AddOwner( + o => o._overlayInputPassThroughElement, + (o, v) => o._overlayInputPassThroughElement = v); + /// /// Defines the AttachedFlyout property /// @@ -57,6 +60,12 @@ namespace Avalonia.Controls.Primitives private PixelRect? _enlargePopupRectScreenPixelRect; private IDisposable? _transientDisposable; private Action? _popupHostChangedHandler; + private IInputElement? _overlayInputPassThroughElement; + + static FlyoutBase() + { + Control.ContextFlyoutProperty.Changed.Subscribe(OnContextFlyoutPropertyChanged); + } public FlyoutBase() { @@ -101,11 +110,21 @@ namespace Avalonia.Controls.Primitives private set => SetAndRaise(TargetProperty, ref _target, value); } + /// + /// Gets or sets an element that should receive pointer input events even when underneath + /// the flyout's overlay. + /// + public IInputElement? OverlayInputPassThroughElement + { + get => _overlayInputPassThroughElement; + set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value); + } + IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host; - event Action? IPopupHostProvider.PopupHostChanged - { - add => _popupHostChangedHandler += value; + event Action? IPopupHostProvider.PopupHostChanged + { + add => _popupHostChangedHandler += value; remove => _popupHostChangedHandler -= value; } @@ -175,8 +194,9 @@ namespace Avalonia.Controls.Primitives IsOpen = false; Popup.IsOpen = false; + ((ISetLogicalParent)Popup).SetParent(null); - + // Ensure this isn't active _transientDisposable?.Dispose(); _transientDisposable = null; @@ -231,6 +251,8 @@ namespace Avalonia.Controls.Primitives Popup.Child = CreatePresenter(); } + Popup.OverlayInputPassThroughElement = OverlayInputPassThroughElement; + if (CancelOpening()) { return false; @@ -356,10 +378,13 @@ namespace Avalonia.Controls.Primitives private Popup CreatePopup() { - var popup = new Popup(); - popup.WindowManagerAddShadowHint = false; - popup.IsLightDismissEnabled = true; - popup.OverlayDismissEventPassThrough = true; + var popup = new Popup + { + WindowManagerAddShadowHint = false, + IsLightDismissEnabled = true, + //Note: This is required to prevent Button.Flyout from opening the flyout again after dismiss. + OverlayDismissEventPassThrough = false + }; popup.Opened += OnPopupOpened; popup.Closed += OnPopupClosed; @@ -372,7 +397,7 @@ namespace Avalonia.Controls.Primitives { IsOpen = true; - _popupHostChangedHandler?.Invoke(Popup!.Host); + _popupHostChangedHandler?.Invoke(Popup.Host); } private void OnPopupClosing(object? sender, CancelEventArgs e) diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs index 79285bb86b..80b5259a53 100644 --- a/src/Avalonia.Controls/ListBox.cs +++ b/src/Avalonia.Controls/ListBox.cs @@ -6,6 +6,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Selection; using Avalonia.Controls.Templates; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.VisualTree; namespace Avalonia.Controls @@ -157,7 +158,7 @@ namespace Avalonia.Controls e.Source, true, e.KeyModifiers.HasAllFlags(KeyModifiers.Shift), - e.KeyModifiers.HasAllFlags(KeyModifiers.Control), + e.KeyModifiers.HasAllFlags(AvaloniaLocator.Current.GetRequiredService().CommandModifiers), point.Properties.IsRightButtonPressed); } } diff --git a/src/Avalonia.Controls/Platform/PlatformManager.cs b/src/Avalonia.Controls/Platform/PlatformManager.cs index 92f6f1cb52..de7708e869 100644 --- a/src/Avalonia.Controls/Platform/PlatformManager.cs +++ b/src/Avalonia.Controls/Platform/PlatformManager.cs @@ -20,17 +20,8 @@ namespace Avalonia.Controls.Platform { } - public static ITrayIconImpl? CreateTrayIcon() - { - var platform = AvaloniaLocator.Current.GetService(); - - if (platform == null) - { - throw new Exception("Could not CreateTrayIcon(): IWindowingPlatform is not registered."); - } - - return s_designerMode ? null : platform.CreateTrayIcon(); - } + public static ITrayIconImpl? CreateTrayIcon() => + s_designerMode ? null : AvaloniaLocator.Current.GetService()?.CreateTrayIcon(); public static IWindowImpl CreateWindow() diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs index 39a512a773..4db2ec6d50 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs +++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs @@ -187,7 +187,7 @@ namespace Avalonia.Controls.Presenters break; case NotifyCollectionChangedAction.Remove: - if ((e.OldStartingIndex >= FirstIndex && e.OldStartingIndex < NextIndex) || + if (e.OldStartingIndex < NextIndex || panel.Children.Count > ItemCount) { RecycleContainersOnRemove(); diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index e463bc5731..e540f58195 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -9,6 +9,7 @@ using Avalonia.VisualTree; using Avalonia.Layout; using Avalonia.Media.Immutable; using Avalonia.Controls.Documents; +using Avalonia.Media.TextFormatting.Unicode; namespace Avalonia.Controls.Presenters { @@ -496,14 +497,14 @@ namespace Avalonia.Controls.Presenters var length = Math.Max(selectionStart, selectionEnd) - start; IReadOnlyList>? textStyleOverrides = null; - - if (length > 0) + + if (length > 0 && SelectionForegroundBrush != null) { textStyleOverrides = new[] { new ValueSpan(start, length, new GenericTextRunProperties(typeface, FontSize, - foregroundBrush: SelectionForegroundBrush ?? Brushes.White)) + foregroundBrush: SelectionForegroundBrush)) }; } diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 1501d97470..3573ad9aaa 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -501,7 +501,7 @@ namespace Avalonia.Controls.Primitives if (dismissLayer != null) { dismissLayer.IsVisible = true; - dismissLayer.InputPassThroughElement = _overlayInputPassThroughElement; + dismissLayer.InputPassThroughElement = OverlayInputPassThroughElement; Disposable.Create(() => { diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs index 56b9caf085..91114628ee 100644 --- a/src/Avalonia.Controls/ProgressBar.cs +++ b/src/Avalonia.Controls/ProgressBar.cs @@ -119,14 +119,12 @@ namespace Avalonia.Controls nameof(Percentage), o => o.Percentage); - [Obsolete("To be removed when Avalonia.Themes.Default is discontinued.")] public static readonly DirectProperty IndeterminateStartingOffsetProperty = AvaloniaProperty.RegisterDirect( nameof(IndeterminateStartingOffset), p => p.IndeterminateStartingOffset, (p, o) => p.IndeterminateStartingOffset = o); - [Obsolete("To be removed when Avalonia.Themes.Default is discontinued.")] public static readonly DirectProperty IndeterminateEndingOffsetProperty = AvaloniaProperty.RegisterDirect( nameof(IndeterminateEndingOffset), @@ -139,14 +137,12 @@ namespace Avalonia.Controls private set { SetAndRaise(PercentageProperty, ref _percentage, value); } } - [Obsolete("To be removed when Avalonia.Themes.Default is discontinued.")] public double IndeterminateStartingOffset { get => _indeterminateStartingOffset; set => SetAndRaise(IndeterminateStartingOffsetProperty, ref _indeterminateStartingOffset, value); } - [Obsolete("To be removed when Avalonia.Themes.Default is discontinued.")] public double IndeterminateEndingOffset { get => _indeterminateEndingOffset; diff --git a/src/Avalonia.Controls/RichTextBlock.cs b/src/Avalonia.Controls/RichTextBlock.cs index 0c8b1d125d..1f8abbc30d 100644 --- a/src/Avalonia.Controls/RichTextBlock.cs +++ b/src/Avalonia.Controls/RichTextBlock.cs @@ -44,8 +44,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty InlinesProperty = - AvaloniaProperty.Register( + public static readonly StyledProperty InlinesProperty = + AvaloniaProperty.Register( nameof(Inlines)); public static readonly DirectProperty CanCopyProperty = @@ -138,7 +138,7 @@ namespace Avalonia.Controls /// Gets or sets the inlines. /// [Content] - public InlineCollection Inlines + public InlineCollection? Inlines { get => GetValue(InlinesProperty); set => SetValue(InlinesProperty, value); @@ -159,7 +159,7 @@ namespace Avalonia.Controls remove => RemoveHandler(CopyingToClipboardEvent, value); } - internal bool HasComplexContent => Inlines.Count > 0; + internal bool HasComplexContent => Inlines != null && Inlines.Count > 0; /// /// Copies the current selection to the Clipboard. @@ -260,23 +260,23 @@ namespace Avalonia.Controls { if (!string.IsNullOrEmpty(_text)) { - Inlines.Add(_text); + Inlines?.Add(_text); _text = null; } - Inlines.Add(text); + Inlines?.Add(text); } } protected override string? GetText() { - return _text ?? Inlines.Text; + return _text ?? Inlines?.Text; } protected override void SetText(string? text) { - var oldValue = _text ?? Inlines?.Text; + var oldValue = GetText(); AddText(text); @@ -301,10 +301,10 @@ namespace Avalonia.Controls ITextSource textSource; - var inlines = Inlines; - if (HasComplexContent) { + var inlines = Inlines!; + var textRuns = new List(); foreach (var inline in inlines) @@ -537,7 +537,7 @@ namespace Avalonia.Controls switch (change.Property.Name) { - case nameof(InlinesProperty): + case nameof(Inlines): { OnInlinesChanged(change.OldValue as InlineCollection, change.NewValue as InlineCollection); InvalidateTextLayout(); @@ -553,7 +553,7 @@ namespace Avalonia.Controls return ""; } - var text = Inlines.Text ?? Text; + var text = GetText(); if (string.IsNullOrEmpty(text)) { diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 1b268db2f7..4c9e9327d4 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -17,6 +17,7 @@ using Avalonia.Controls.Metadata; using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Automation.Peers; +using System.Diagnostics; namespace Avalonia.Controls { @@ -1240,9 +1241,10 @@ namespace Avalonia.Controls MathUtilities.Clamp(point.X, 0, Math.Max(_presenter.Bounds.Width - 1, 0)), MathUtilities.Clamp(point.Y, 0, Math.Max(_presenter.Bounds.Height - 1, 0))); - _presenter.MoveCaretToPoint(point); + _presenter.MoveCaretToPoint(point); var caretIndex = _presenter.CaretIndex; + var text = Text; if (text != null && _wordSelectionStart >= 0) @@ -1266,7 +1268,7 @@ namespace Avalonia.Controls } else { - SelectionEnd = _presenter.CaretIndex; + SelectionEnd = caretIndex; } } } diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index b2a188a2ea..7359f3cade 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -529,7 +529,7 @@ namespace Avalonia.Controls e.Source, true, e.KeyModifiers.HasAllFlags(KeyModifiers.Shift), - e.KeyModifiers.HasAllFlags(KeyModifiers.Control), + e.KeyModifiers.HasAllFlags(AvaloniaLocator.Current.GetRequiredService().CommandModifiers), point.Properties.IsRightButtonPressed); } } diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index adddf3f57b..d719135a7f 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml index c32638f6ca..1270dbaa62 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml @@ -2,19 +2,16 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views="clr-namespace:Avalonia.Diagnostics.Views" xmlns:diag="clr-namespace:Avalonia.Diagnostics" - xmlns:default="using:Avalonia.Themes.Default" Title="Avalonia DevTools" - x:Class="Avalonia.Diagnostics.Views.MainWindow"> + x:Class="Avalonia.Diagnostics.Views.MainWindow" + Theme="{StaticResource {x:Type Window}}"> - - - + + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 96dc929434..c81997f2cb 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -11,7 +11,7 @@ using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Markup.Xaml; using Avalonia.Styling; -using Avalonia.Themes.Default; +using Avalonia.Themes.Simple; using Avalonia.VisualTree; namespace Avalonia.Diagnostics.Views diff --git a/src/Avalonia.Themes.Default/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Default/Controls/ButtonSpinner.xaml deleted file mode 100644 index 561ca8bedd..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ButtonSpinner.xaml +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Default/Controls/CalendarButton.xaml deleted file mode 100644 index 3314534b3b..0000000000 --- a/src/Avalonia.Themes.Default/Controls/CalendarButton.xaml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/CalendarDayButton.xaml b/src/Avalonia.Themes.Default/Controls/CalendarDayButton.xaml deleted file mode 100644 index 2d79e62a75..0000000000 --- a/src/Avalonia.Themes.Default/Controls/CalendarDayButton.xaml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml b/src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml deleted file mode 100644 index be6642467f..0000000000 --- a/src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/Carousel.xaml b/src/Avalonia.Themes.Default/Controls/Carousel.xaml deleted file mode 100644 index baba0649aa..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Carousel.xaml +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/ComboBoxItem.xaml b/src/Avalonia.Themes.Default/Controls/ComboBoxItem.xaml deleted file mode 100644 index a694143bec..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ComboBoxItem.xaml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ContentControl.xaml b/src/Avalonia.Themes.Default/Controls/ContentControl.xaml deleted file mode 100644 index d32bc399b6..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ContentControl.xaml +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/ContextMenu.xaml b/src/Avalonia.Themes.Default/Controls/ContextMenu.xaml deleted file mode 100644 index 987b72aaa2..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ContextMenu.xaml +++ /dev/null @@ -1,25 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/DataValidationErrors.xaml b/src/Avalonia.Themes.Default/Controls/DataValidationErrors.xaml deleted file mode 100644 index d7bf4bbbf1..0000000000 --- a/src/Avalonia.Themes.Default/Controls/DataValidationErrors.xaml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/DatePicker.xaml b/src/Avalonia.Themes.Default/Controls/DatePicker.xaml deleted file mode 100644 index c1ee941416..0000000000 --- a/src/Avalonia.Themes.Default/Controls/DatePicker.xaml +++ /dev/null @@ -1,337 +0,0 @@ - - - - - 0,0,0,4 - 40 - 40 - 41 - 296 - 456 - 0,3,0,6 - 9,3,0,6 - 0,3,0,6 - 9,3,0,6 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Default/Controls/EmbeddableControlRoot.xaml deleted file mode 100644 index 9ffe51fae8..0000000000 --- a/src/Avalonia.Themes.Default/Controls/EmbeddableControlRoot.xaml +++ /dev/null @@ -1,19 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/Expander.xaml b/src/Avalonia.Themes.Default/Controls/Expander.xaml deleted file mode 100644 index 2f18faf84a..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Expander.xaml +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - Expanded content - - - - - Expanded content - - - - - Expanded content - - - - - Expanded content - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/FocusAdorner.xaml b/src/Avalonia.Themes.Default/Controls/FocusAdorner.xaml deleted file mode 100644 index 2d5e369573..0000000000 --- a/src/Avalonia.Themes.Default/Controls/FocusAdorner.xaml +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/GridSplitter.xaml b/src/Avalonia.Themes.Default/Controls/GridSplitter.xaml deleted file mode 100644 index 490ae01318..0000000000 --- a/src/Avalonia.Themes.Default/Controls/GridSplitter.xaml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ItemsControl.xaml b/src/Avalonia.Themes.Default/Controls/ItemsControl.xaml deleted file mode 100644 index 19d13b6399..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ItemsControl.xaml +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/Label.xaml b/src/Avalonia.Themes.Default/Controls/Label.xaml deleted file mode 100644 index 1e04d05497..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Label.xaml +++ /dev/null @@ -1,18 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/ListBox.xaml b/src/Avalonia.Themes.Default/Controls/ListBox.xaml deleted file mode 100644 index b1fcb830b3..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ListBox.xaml +++ /dev/null @@ -1,35 +0,0 @@ - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ListBoxItem.xaml b/src/Avalonia.Themes.Default/Controls/ListBoxItem.xaml deleted file mode 100644 index c1360c5d98..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ListBoxItem.xaml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ManagedFileChooser.xaml b/src/Avalonia.Themes.Default/Controls/ManagedFileChooser.xaml deleted file mode 100644 index f9f77bf455..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ManagedFileChooser.xaml +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Controls/Menu.xaml b/src/Avalonia.Themes.Default/Controls/Menu.xaml deleted file mode 100644 index 583add1017..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Menu.xaml +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/MenuItem.xaml b/src/Avalonia.Themes.Default/Controls/MenuItem.xaml deleted file mode 100644 index 05c286c1f5..0000000000 --- a/src/Avalonia.Themes.Default/Controls/MenuItem.xaml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/NativeMenuBar.xaml b/src/Avalonia.Themes.Default/Controls/NativeMenuBar.xaml deleted file mode 100644 index 3b0019eea1..0000000000 --- a/src/Avalonia.Themes.Default/Controls/NativeMenuBar.xaml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/NotificationCard.xaml b/src/Avalonia.Themes.Default/Controls/NotificationCard.xaml deleted file mode 100644 index c411fede11..0000000000 --- a/src/Avalonia.Themes.Default/Controls/NotificationCard.xaml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml b/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml deleted file mode 100644 index 07d905ea1d..0000000000 --- a/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml +++ /dev/null @@ -1,23 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/PathIcon.xaml b/src/Avalonia.Themes.Default/Controls/PathIcon.xaml deleted file mode 100644 index 039f0ef10c..0000000000 --- a/src/Avalonia.Themes.Default/Controls/PathIcon.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - diff --git a/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml b/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml deleted file mode 100644 index 5e8f3337ee..0000000000 --- a/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml +++ /dev/null @@ -1,27 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/ProgressBar.xaml b/src/Avalonia.Themes.Default/Controls/ProgressBar.xaml deleted file mode 100644 index 3f684f3936..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ProgressBar.xaml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/RadioButton.xaml b/src/Avalonia.Themes.Default/Controls/RadioButton.xaml deleted file mode 100644 index ae33946009..0000000000 --- a/src/Avalonia.Themes.Default/Controls/RadioButton.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/RepeatButton.xaml b/src/Avalonia.Themes.Default/Controls/RepeatButton.xaml deleted file mode 100644 index 47398966f7..0000000000 --- a/src/Avalonia.Themes.Default/Controls/RepeatButton.xaml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/RichTextBlock.xaml b/src/Avalonia.Themes.Default/Controls/RichTextBlock.xaml deleted file mode 100644 index d7bf6e5cf9..0000000000 --- a/src/Avalonia.Themes.Default/Controls/RichTextBlock.xaml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ScrollBar.xaml b/src/Avalonia.Themes.Default/Controls/ScrollBar.xaml deleted file mode 100644 index 0f8fa4986d..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ScrollBar.xaml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/Separator.xaml b/src/Avalonia.Themes.Default/Controls/Separator.xaml deleted file mode 100644 index 6a318d2e85..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Separator.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/Slider.xaml b/src/Avalonia.Themes.Default/Controls/Slider.xaml deleted file mode 100644 index bcb330f188..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Slider.xaml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/SplitButton.xaml b/src/Avalonia.Themes.Default/Controls/SplitButton.xaml deleted file mode 100644 index 0c46ce3724..0000000000 --- a/src/Avalonia.Themes.Default/Controls/SplitButton.xaml +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - - - - - 24 - 24 - 1 - 24 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/SplitView.xaml b/src/Avalonia.Themes.Default/Controls/SplitView.xaml deleted file mode 100644 index 10eda2d9cd..0000000000 --- a/src/Avalonia.Themes.Default/Controls/SplitView.xaml +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - 320 - 48 - - 00:00:00.2 - 00:00:00.1 - 0.1,0.9,0.2,1.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/TabControl.xaml b/src/Avalonia.Themes.Default/Controls/TabControl.xaml deleted file mode 100644 index afb5010baa..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TabControl.xaml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/TabItem.xaml b/src/Avalonia.Themes.Default/Controls/TabItem.xaml deleted file mode 100644 index c7748299a0..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TabItem.xaml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/TextBox.xaml b/src/Avalonia.Themes.Default/Controls/TextBox.xaml deleted file mode 100644 index 1885d3b65b..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TextBox.xaml +++ /dev/null @@ -1,203 +0,0 @@ - - - M 11.416016,10 20,1.4160156 18.583984,0 10,8.5839846 1.4160156,0 0,1.4160156 8.5839844,10 0,18.583985 1.4160156,20 10,11.416015 18.583984,20 20,18.583985 Z - m10.051 7.0032c2.215 0 4.0105 1.7901 4.0105 3.9984s-1.7956 3.9984-4.0105 3.9984c-2.215 0-4.0105-1.7901-4.0105-3.9984s1.7956-3.9984 4.0105-3.9984zm0 1.4994c-1.3844 0-2.5066 1.1188-2.5066 2.499s1.1222 2.499 2.5066 2.499 2.5066-1.1188 2.5066-2.499-1.1222-2.499-2.5066-2.499zm0-5.0026c4.6257 0 8.6188 3.1487 9.7267 7.5613 0.10085 0.40165-0.14399 0.80877-0.54686 0.90931-0.40288 0.10054-0.81122-0.14355-0.91208-0.54521-0.94136-3.7492-4.3361-6.4261-8.2678-6.4261-3.9334 0-7.3292 2.6792-8.2689 6.4306-0.10063 0.40171-0.50884 0.64603-0.91177 0.54571s-0.648-0.5073-0.54737-0.90901c1.106-4.4152 5.1003-7.5667 9.728-7.5667z - m0.21967 0.21965c-0.26627 0.26627-0.29047 0.68293-0.07262 0.97654l0.07262 0.08412 4.0346 4.0346c-1.922 1.3495-3.3585 3.365-3.9554 5.7495-0.10058 0.4018 0.14362 0.8091 0.54543 0.9097 0.40182 0.1005 0.80909-0.1436 0.90968-0.5455 0.52947-2.1151 1.8371-3.8891 3.5802-5.0341l1.8096 1.8098c-0.70751 0.7215-1.1438 1.71-1.1438 2.8003 0 2.2092 1.7909 4 4 4 1.0904 0 2.0788-0.4363 2.8004-1.1438l5.9193 5.9195c0.2929 0.2929 0.7677 0.2929 1.0606 0 0.2663-0.2662 0.2905-0.6829 0.0726-0.9765l-0.0726-0.0841-6.1135-6.1142 0.0012-0.0015-1.2001-1.1979-2.8699-2.8693 2e-3 -8e-4 -2.8812-2.8782 0.0012-0.0018-1.1333-1.1305-4.3064-4.3058c-0.29289-0.29289-0.76777-0.29289-1.0607 0zm7.9844 9.0458 3.5351 3.5351c-0.45 0.4358-1.0633 0.704-1.7392 0.704-1.3807 0-2.5-1.1193-2.5-2.5 0-0.6759 0.26824-1.2892 0.7041-1.7391zm1.7959-5.7655c-1.0003 0-1.9709 0.14807-2.8889 0.425l1.237 1.2362c0.5358-0.10587 1.0883-0.16119 1.6519-0.16119 3.9231 0 7.3099 2.6803 8.2471 6.4332 0.1004 0.4018 0.5075 0.6462 0.9094 0.5459 0.4019-0.1004 0.6463-0.5075 0.5459-0.9094-1.103-4.417-5.0869-7.5697-9.7024-7.5697zm0.1947 3.5093 3.8013 3.8007c-0.1018-2.0569-1.7488-3.7024-3.8013-3.8007z - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/TimePicker.xaml b/src/Avalonia.Themes.Default/Controls/TimePicker.xaml deleted file mode 100644 index 0a5147e335..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TimePicker.xaml +++ /dev/null @@ -1,286 +0,0 @@ - - - - - 40 - 1 - 1 - 0,0,0,4 - 40 - 41 - 242 - 456 - 0,3,0,6 - 0,3,0,6 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/TitleBar.xaml b/src/Avalonia.Themes.Default/Controls/TitleBar.xaml deleted file mode 100644 index 7f8ed24076..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TitleBar.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ToggleSwitch.xaml b/src/Avalonia.Themes.Default/Controls/ToggleSwitch.xaml deleted file mode 100644 index 2c831cf360..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ToggleSwitch.xaml +++ /dev/null @@ -1,322 +0,0 @@ - - - 0,0,0,6 - 6 - 6 - 0 - 0 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/ToolTip.xaml b/src/Avalonia.Themes.Default/Controls/ToolTip.xaml deleted file mode 100644 index 35c1dceb8d..0000000000 --- a/src/Avalonia.Themes.Default/Controls/ToolTip.xaml +++ /dev/null @@ -1,18 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/TreeView.xaml b/src/Avalonia.Themes.Default/Controls/TreeView.xaml deleted file mode 100644 index 67a683dad9..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TreeView.xaml +++ /dev/null @@ -1,27 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/TreeViewItem.xaml b/src/Avalonia.Themes.Default/Controls/TreeViewItem.xaml deleted file mode 100644 index 1996756001..0000000000 --- a/src/Avalonia.Themes.Default/Controls/TreeViewItem.xaml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/Controls/UserControl.xaml b/src/Avalonia.Themes.Default/Controls/UserControl.xaml deleted file mode 100644 index d6028daff8..0000000000 --- a/src/Avalonia.Themes.Default/Controls/UserControl.xaml +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/Window.xaml b/src/Avalonia.Themes.Default/Controls/Window.xaml deleted file mode 100644 index 9c515ebe30..0000000000 --- a/src/Avalonia.Themes.Default/Controls/Window.xaml +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/src/Avalonia.Themes.Default/Controls/WindowNotificationManager.xaml b/src/Avalonia.Themes.Default/Controls/WindowNotificationManager.xaml deleted file mode 100644 index 7c1efa2e82..0000000000 --- a/src/Avalonia.Themes.Default/Controls/WindowNotificationManager.xaml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml deleted file mode 100644 index f266402aef..0000000000 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs b/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs deleted file mode 100644 index 598b418977..0000000000 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Avalonia.Styling; - -namespace Avalonia.Themes.Default -{ - /// - /// The default Avalonia theme. - /// - public class DefaultTheme : Styles - { - } -} diff --git a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml index 855dc5363e..aa55065f6d 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml @@ -41,13 +41,31 @@ M0,9 L10,0 20,9 19,10 10,2 1,10 z M0,1 L10,10 20,1 19,0 10,8 1,0 z - - + - + + + + + + + + + @@ -83,7 +101,6 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness, Converter={StaticResource ButtonSpinnerLeftThickness}}" - CornerRadius="0" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Foreground="{TemplateBinding Foreground}" @@ -99,7 +116,6 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness, Converter={StaticResource ButtonSpinnerLeftThickness}}" - CornerRadius="0" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Foreground="{TemplateBinding Foreground}" diff --git a/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml b/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml index 8365ee61d3..fdd79ed736 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml @@ -29,7 +29,7 @@ - + 0,4,0,4 @@ -54,7 +54,7 @@ MinHeight="{TemplateBinding MinHeight}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" CornerRadius="{TemplateBinding CornerRadius}"> - + @@ -26,10 +25,33 @@ - - - - + + + + + + + + + + + + - + - - - - - - - - - + diff --git a/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml b/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml index 0499495239..577539b26b 100644 --- a/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml @@ -75,5 +75,4 @@ - diff --git a/src/Avalonia.Themes.Fluent/Controls/Menu.xaml b/src/Avalonia.Themes.Fluent/Controls/Menu.xaml index 12d18ae644..f5fd69a67f 100644 --- a/src/Avalonia.Themes.Fluent/Controls/Menu.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/Menu.xaml @@ -5,7 +5,7 @@ - + @@ -46,7 +46,7 @@ MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}" HorizontalAlignment="Stretch" CornerRadius="{DynamicResource OverlayCornerRadius}"> - + - + - - + + diff --git a/src/Avalonia.Themes.Default/Controls/ToggleButton.xaml b/src/Avalonia.Themes.Simple/Controls/Button.xaml similarity index 53% rename from src/Avalonia.Themes.Default/Controls/ToggleButton.xaml rename to src/Avalonia.Themes.Simple/Controls/Button.xaml index 17fb2af16c..9018677ab6 100644 --- a/src/Avalonia.Themes.Default/Controls/ToggleButton.xaml +++ b/src/Avalonia.Themes.Simple/Controls/Button.xaml @@ -1,40 +1,38 @@ - - - - - - - + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Simple/Controls/ButtonSpinner.xaml new file mode 100644 index 0000000000..9798e5290b --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ButtonSpinner.xaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/Calendar.xaml b/src/Avalonia.Themes.Simple/Controls/Calendar.xaml similarity index 65% rename from src/Avalonia.Themes.Default/Controls/Calendar.xaml rename to src/Avalonia.Themes.Simple/Controls/Calendar.xaml index 4b67aa232b..6f7267581b 100644 --- a/src/Avalonia.Themes.Default/Controls/Calendar.xaml +++ b/src/Avalonia.Themes.Simple/Controls/Calendar.xaml @@ -1,12 +1,14 @@ - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml new file mode 100644 index 0000000000..59fb24663f --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml similarity index 64% rename from src/Avalonia.Themes.Default/Controls/CalendarDatePicker.xaml rename to src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml index 3e2e497d2c..43fc8c7a34 100644 --- a/src/Avalonia.Themes.Default/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml @@ -1,20 +1,21 @@ - - - + - + + UseFloatingWatermark="{TemplateBinding UseFloatingWatermark}" + Watermark="{TemplateBinding Watermark}" /> - + + Margin="6,-1,6,6" + IsVisible="False"> @@ -132,8 +133,8 @@ + Margin="6,-3,7,6" + IsVisible="False"> @@ -146,39 +147,33 @@ - - + Stretch="Fill" /> - - - - - - - + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/CaptionButtons.xaml b/src/Avalonia.Themes.Simple/Controls/CaptionButtons.xaml new file mode 100644 index 0000000000..379b92ea17 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/CaptionButtons.xaml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/Carousel.xaml b/src/Avalonia.Themes.Simple/Controls/Carousel.xaml new file mode 100644 index 0000000000..e79e3942c9 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/Carousel.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/CheckBox.xaml b/src/Avalonia.Themes.Simple/Controls/CheckBox.xaml similarity index 57% rename from src/Avalonia.Themes.Default/Controls/CheckBox.xaml rename to src/Avalonia.Themes.Simple/Controls/CheckBox.xaml index 170ecdd5b8..10e0b883d5 100644 --- a/src/Avalonia.Themes.Default/Controls/CheckBox.xaml +++ b/src/Avalonia.Themes.Simple/Controls/CheckBox.xaml @@ -1,72 +1,75 @@ - - - - - - - - - + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/ComboBox.xaml b/src/Avalonia.Themes.Simple/Controls/ComboBox.xaml similarity index 65% rename from src/Avalonia.Themes.Default/Controls/ComboBox.xaml rename to src/Avalonia.Themes.Simple/Controls/ComboBox.xaml index 262f63e2d2..d7dabae516 100644 --- a/src/Avalonia.Themes.Default/Controls/ComboBox.xaml +++ b/src/Avalonia.Themes.Simple/Controls/ComboBox.xaml @@ -1,23 +1,7 @@ - - - - - - Item 1 - Item 2 - - - Item 1 - Item 2 - - - - - - - - + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ComboBoxItem.xaml b/src/Avalonia.Themes.Simple/Controls/ComboBoxItem.xaml new file mode 100644 index 0000000000..c3d8b6f900 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ComboBoxItem.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ContentControl.xaml b/src/Avalonia.Themes.Simple/Controls/ContentControl.xaml new file mode 100644 index 0000000000..415b1dc721 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ContentControl.xaml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ContextMenu.xaml b/src/Avalonia.Themes.Simple/Controls/ContextMenu.xaml new file mode 100644 index 0000000000..e99f1c5ac0 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ContextMenu.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/DataValidationErrors.xaml b/src/Avalonia.Themes.Simple/Controls/DataValidationErrors.xaml new file mode 100644 index 0000000000..da8ec03cd4 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/DataValidationErrors.xaml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml b/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml new file mode 100644 index 0000000000..a6da2ad9f8 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + Error + + + + + + + + + 0,0,0,4 + 40 + 40 + 41 + 296 + 456 + 0,3,0,6 + 9,3,0,6 + 0,3,0,6 + 9,3,0,6 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml b/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml new file mode 100644 index 0000000000..5909a1abbf --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml @@ -0,0 +1,139 @@ + + + + + + + Standard Item + Month Item + Button + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/DropDownButton.xaml b/src/Avalonia.Themes.Simple/Controls/DropDownButton.xaml similarity index 54% rename from src/Avalonia.Themes.Default/Controls/DropDownButton.xaml rename to src/Avalonia.Themes.Simple/Controls/DropDownButton.xaml index 662c6379fb..6a50cd6e36 100644 --- a/src/Avalonia.Themes.Default/Controls/DropDownButton.xaml +++ b/src/Avalonia.Themes.Simple/Controls/DropDownButton.xaml @@ -1,12 +1,14 @@ - - - + - + - + - - + + + diff --git a/src/Avalonia.Themes.Simple/Controls/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Simple/Controls/EmbeddableControlRoot.xaml new file mode 100644 index 0000000000..79d6c6d917 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/EmbeddableControlRoot.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/Expander.xaml b/src/Avalonia.Themes.Simple/Controls/Expander.xaml new file mode 100644 index 0000000000..9920c9445a --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/Expander.xaml @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/FlyoutPresenter.xaml b/src/Avalonia.Themes.Simple/Controls/FlyoutPresenter.xaml similarity index 78% rename from src/Avalonia.Themes.Default/Controls/FlyoutPresenter.xaml rename to src/Avalonia.Themes.Simple/Controls/FlyoutPresenter.xaml index 3bc5e085ff..08959cfbbe 100644 --- a/src/Avalonia.Themes.Default/Controls/FlyoutPresenter.xaml +++ b/src/Avalonia.Themes.Simple/Controls/FlyoutPresenter.xaml @@ -1,8 +1,10 @@ - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/FocusAdorner.xaml b/src/Avalonia.Themes.Simple/Controls/FocusAdorner.xaml new file mode 100644 index 0000000000..f1d5f5f2ac --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/FocusAdorner.xaml @@ -0,0 +1,11 @@ + diff --git a/src/Avalonia.Themes.Simple/Controls/GridSplitter.xaml b/src/Avalonia.Themes.Simple/Controls/GridSplitter.xaml new file mode 100644 index 0000000000..f2a3f01397 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/GridSplitter.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ItemsControl.xaml b/src/Avalonia.Themes.Simple/Controls/ItemsControl.xaml new file mode 100644 index 0000000000..d8cdf96abd --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ItemsControl.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/TabStripItem.xaml b/src/Avalonia.Themes.Simple/Controls/Label.xaml similarity index 59% rename from src/Avalonia.Themes.Default/Controls/TabStripItem.xaml rename to src/Avalonia.Themes.Simple/Controls/Label.xaml index 61eecc0395..0faa4852f2 100644 --- a/src/Avalonia.Themes.Default/Controls/TabStripItem.xaml +++ b/src/Avalonia.Themes.Simple/Controls/Label.xaml @@ -1,24 +1,22 @@ - - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/ListBox.xaml b/src/Avalonia.Themes.Simple/Controls/ListBox.xaml new file mode 100644 index 0000000000..7308738681 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ListBox.xaml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ListBoxItem.xaml b/src/Avalonia.Themes.Simple/Controls/ListBoxItem.xaml new file mode 100644 index 0000000000..4d918326c8 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ListBoxItem.xaml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ManagedFileChooser.xaml b/src/Avalonia.Themes.Simple/Controls/ManagedFileChooser.xaml new file mode 100644 index 0000000000..52d9000396 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ManagedFileChooser.xaml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Show hidden files + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/Menu.xaml b/src/Avalonia.Themes.Simple/Controls/Menu.xaml new file mode 100644 index 0000000000..95b259bfa6 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/Menu.xaml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/MenuFlyoutPresenter.xaml b/src/Avalonia.Themes.Simple/Controls/MenuFlyoutPresenter.xaml similarity index 76% rename from src/Avalonia.Themes.Default/Controls/MenuFlyoutPresenter.xaml rename to src/Avalonia.Themes.Simple/Controls/MenuFlyoutPresenter.xaml index d56b46b17c..d974c36d31 100644 --- a/src/Avalonia.Themes.Default/Controls/MenuFlyoutPresenter.xaml +++ b/src/Avalonia.Themes.Simple/Controls/MenuFlyoutPresenter.xaml @@ -1,6 +1,8 @@ - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/MenuItem.xaml b/src/Avalonia.Themes.Simple/Controls/MenuItem.xaml new file mode 100644 index 0000000000..ec22ee413d --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/MenuItem.xaml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/NativeMenuBar.xaml b/src/Avalonia.Themes.Simple/Controls/NativeMenuBar.xaml new file mode 100644 index 0000000000..8c51ec8609 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/NativeMenuBar.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/NotificationCard.xaml b/src/Avalonia.Themes.Simple/Controls/NotificationCard.xaml new file mode 100644 index 0000000000..524f964afc --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/NotificationCard.xaml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/NumericUpDown.xaml b/src/Avalonia.Themes.Simple/Controls/NumericUpDown.xaml similarity index 71% rename from src/Avalonia.Themes.Default/Controls/NumericUpDown.xaml rename to src/Avalonia.Themes.Simple/Controls/NumericUpDown.xaml index 6740be69bb..d3adfb31e0 100644 --- a/src/Avalonia.Themes.Default/Controls/NumericUpDown.xaml +++ b/src/Avalonia.Themes.Simple/Controls/NumericUpDown.xaml @@ -1,40 +1,39 @@ - - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml b/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml new file mode 100644 index 0000000000..d1f5585c02 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/PathIcon.xaml b/src/Avalonia.Themes.Simple/Controls/PathIcon.xaml new file mode 100644 index 0000000000..4116b5784e --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/PathIcon.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml b/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml new file mode 100644 index 0000000000..a5593e3a68 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ProgressBar.xaml b/src/Avalonia.Themes.Simple/Controls/ProgressBar.xaml new file mode 100644 index 0000000000..5adb5bde7e --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ProgressBar.xaml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/RadioButton.xaml b/src/Avalonia.Themes.Simple/Controls/RadioButton.xaml new file mode 100644 index 0000000000..c837b44402 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/RadioButton.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/Button.xaml b/src/Avalonia.Themes.Simple/Controls/RepeatButton.xaml similarity index 58% rename from src/Avalonia.Themes.Default/Controls/Button.xaml rename to src/Avalonia.Themes.Simple/Controls/RepeatButton.xaml index a2971c3ff6..73cfd4d810 100644 --- a/src/Avalonia.Themes.Default/Controls/Button.xaml +++ b/src/Avalonia.Themes.Simple/Controls/RepeatButton.xaml @@ -1,36 +1,34 @@ - - - - - - + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/RichTextBlock.xaml b/src/Avalonia.Themes.Simple/Controls/RichTextBlock.xaml new file mode 100644 index 0000000000..c0570282cb --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/RichTextBlock.xaml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml b/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml new file mode 100644 index 0000000000..d28ba66f6d --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/ScrollViewer.xaml b/src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml similarity index 52% rename from src/Avalonia.Themes.Default/Controls/ScrollViewer.xaml rename to src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml index aab1b76259..e11fbb6f15 100644 --- a/src/Avalonia.Themes.Default/Controls/ScrollViewer.xaml +++ b/src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml @@ -1,106 +1,125 @@ - - + - - + - - + + + diff --git a/src/Avalonia.Themes.Simple/Controls/Separator.xaml b/src/Avalonia.Themes.Simple/Controls/Separator.xaml new file mode 100644 index 0000000000..e142cf29ad --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/Separator.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/SimpleControls.xaml b/src/Avalonia.Themes.Simple/Controls/SimpleControls.xaml new file mode 100644 index 0000000000..644c6ed416 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/SimpleControls.xaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/Slider.xaml b/src/Avalonia.Themes.Simple/Controls/Slider.xaml new file mode 100644 index 0000000000..851ee1b78a --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/Slider.xaml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/SplitButton.xaml b/src/Avalonia.Themes.Simple/Controls/SplitButton.xaml new file mode 100644 index 0000000000..f0d22aac97 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/SplitButton.xaml @@ -0,0 +1,223 @@ + + + + + + + + + + + 24 + 24 + 1 + 24 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/SplitView.xaml b/src/Avalonia.Themes.Simple/Controls/SplitView.xaml new file mode 100644 index 0000000000..b0e4d0b096 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/SplitView.xaml @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + 320 + 48 + + 00:00:00.2 + 00:00:00.1 + 0.1,0.9,0.2,1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/TabControl.xaml b/src/Avalonia.Themes.Simple/Controls/TabControl.xaml new file mode 100644 index 0000000000..4d1fcc0336 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TabControl.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/TabItem.xaml b/src/Avalonia.Themes.Simple/Controls/TabItem.xaml new file mode 100644 index 0000000000..7b6a1d1116 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TabItem.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/TabStrip.xaml b/src/Avalonia.Themes.Simple/Controls/TabStrip.xaml similarity index 63% rename from src/Avalonia.Themes.Default/Controls/TabStrip.xaml rename to src/Avalonia.Themes.Simple/Controls/TabStrip.xaml index 29ca1e7c94..3960c1d275 100644 --- a/src/Avalonia.Themes.Default/Controls/TabStrip.xaml +++ b/src/Avalonia.Themes.Simple/Controls/TabStrip.xaml @@ -1,11 +1,13 @@ - - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/TabStripItem.xaml b/src/Avalonia.Themes.Simple/Controls/TabStripItem.xaml new file mode 100644 index 0000000000..b4d7218ec3 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TabStripItem.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/TextBox.xaml b/src/Avalonia.Themes.Simple/Controls/TextBox.xaml new file mode 100644 index 0000000000..5fa6412688 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TextBox.xaml @@ -0,0 +1,221 @@ + + M 11.416016,10 20,1.4160156 18.583984,0 10,8.5839846 1.4160156,0 0,1.4160156 8.5839844,10 0,18.583985 1.4160156,20 10,11.416015 18.583984,20 20,18.583985 Z + m10.051 7.0032c2.215 0 4.0105 1.7901 4.0105 3.9984s-1.7956 3.9984-4.0105 3.9984c-2.215 0-4.0105-1.7901-4.0105-3.9984s1.7956-3.9984 4.0105-3.9984zm0 1.4994c-1.3844 0-2.5066 1.1188-2.5066 2.499s1.1222 2.499 2.5066 2.499 2.5066-1.1188 2.5066-2.499-1.1222-2.499-2.5066-2.499zm0-5.0026c4.6257 0 8.6188 3.1487 9.7267 7.5613 0.10085 0.40165-0.14399 0.80877-0.54686 0.90931-0.40288 0.10054-0.81122-0.14355-0.91208-0.54521-0.94136-3.7492-4.3361-6.4261-8.2678-6.4261-3.9334 0-7.3292 2.6792-8.2689 6.4306-0.10063 0.40171-0.50884 0.64603-0.91177 0.54571s-0.648-0.5073-0.54737-0.90901c1.106-4.4152 5.1003-7.5667 9.728-7.5667z + m0.21967 0.21965c-0.26627 0.26627-0.29047 0.68293-0.07262 0.97654l0.07262 0.08412 4.0346 4.0346c-1.922 1.3495-3.3585 3.365-3.9554 5.7495-0.10058 0.4018 0.14362 0.8091 0.54543 0.9097 0.40182 0.1005 0.80909-0.1436 0.90968-0.5455 0.52947-2.1151 1.8371-3.8891 3.5802-5.0341l1.8096 1.8098c-0.70751 0.7215-1.1438 1.71-1.1438 2.8003 0 2.2092 1.7909 4 4 4 1.0904 0 2.0788-0.4363 2.8004-1.1438l5.9193 5.9195c0.2929 0.2929 0.7677 0.2929 1.0606 0 0.2663-0.2662 0.2905-0.6829 0.0726-0.9765l-0.0726-0.0841-6.1135-6.1142 0.0012-0.0015-1.2001-1.1979-2.8699-2.8693 2e-3 -8e-4 -2.8812-2.8782 0.0012-0.0018-1.1333-1.1305-4.3064-4.3058c-0.29289-0.29289-0.76777-0.29289-1.0607 0zm7.9844 9.0458 3.5351 3.5351c-0.45 0.4358-1.0633 0.704-1.7392 0.704-1.3807 0-2.5-1.1193-2.5-2.5 0-0.6759 0.26824-1.2892 0.7041-1.7391zm1.7959-5.7655c-1.0003 0-1.9709 0.14807-2.8889 0.425l1.237 1.2362c0.5358-0.10587 1.0883-0.16119 1.6519-0.16119 3.9231 0 7.3099 2.6803 8.2471 6.4332 0.1004 0.4018 0.5075 0.6462 0.9094 0.5459 0.4019-0.1004 0.6463-0.5075 0.5459-0.9094-1.103-4.417-5.0869-7.5697-9.7024-7.5697zm0.1947 3.5093 3.8013 3.8007c-0.1018-2.0569-1.7488-3.7024-3.8013-3.8007z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml b/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml new file mode 100644 index 0000000000..c49b3aec4e --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + Error + + + + + + + + + 40 + 1 + 1 + 0,0,0,4 + 40 + 41 + 242 + 456 + 0,3,0,6 + 0,3,0,6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/TitleBar.xaml b/src/Avalonia.Themes.Simple/Controls/TitleBar.xaml new file mode 100644 index 0000000000..a06dfbb834 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TitleBar.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ToggleButton.xaml b/src/Avalonia.Themes.Simple/Controls/ToggleButton.xaml new file mode 100644 index 0000000000..2cfbcf6b7a --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ToggleButton.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ToggleSwitch.xaml b/src/Avalonia.Themes.Simple/Controls/ToggleSwitch.xaml new file mode 100644 index 0000000000..d00358951a --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ToggleSwitch.xaml @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + 0,0,0,6 + 6 + 6 + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/ToolTip.xaml b/src/Avalonia.Themes.Simple/Controls/ToolTip.xaml new file mode 100644 index 0000000000..c4fddd8c4c --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/ToolTip.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/Controls/TransitioningContentControl.xaml b/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml similarity index 68% rename from src/Avalonia.Themes.Default/Controls/TransitioningContentControl.xaml rename to src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml index 6a4d56ccb7..63185e11e6 100644 --- a/src/Avalonia.Themes.Default/Controls/TransitioningContentControl.xaml +++ b/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml @@ -1,20 +1,21 @@ - - - + + diff --git a/src/Avalonia.Themes.Simple/Controls/TreeView.xaml b/src/Avalonia.Themes.Simple/Controls/TreeView.xaml new file mode 100644 index 0000000000..2bc38a0673 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TreeView.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/TreeViewItem.xaml b/src/Avalonia.Themes.Simple/Controls/TreeViewItem.xaml new file mode 100644 index 0000000000..8b3452244c --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/TreeViewItem.xaml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/UserControl.xaml b/src/Avalonia.Themes.Simple/Controls/UserControl.xaml new file mode 100644 index 0000000000..3316b0298c --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/UserControl.xaml @@ -0,0 +1,25 @@ + diff --git a/src/Avalonia.Themes.Simple/Controls/Window.xaml b/src/Avalonia.Themes.Simple/Controls/Window.xaml new file mode 100644 index 0000000000..00b108343e --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/Window.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Simple/Controls/WindowNotificationManager.xaml b/src/Avalonia.Themes.Simple/Controls/WindowNotificationManager.xaml new file mode 100644 index 0000000000..6dacf63be5 --- /dev/null +++ b/src/Avalonia.Themes.Simple/Controls/WindowNotificationManager.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/IBitmapToImageConverter.cs b/src/Avalonia.Themes.Simple/IBitmapToImageConverter.cs similarity index 95% rename from src/Avalonia.Themes.Default/IBitmapToImageConverter.cs rename to src/Avalonia.Themes.Simple/IBitmapToImageConverter.cs index 9b7fcecf45..fade026b51 100644 --- a/src/Avalonia.Themes.Default/IBitmapToImageConverter.cs +++ b/src/Avalonia.Themes.Simple/IBitmapToImageConverter.cs @@ -8,7 +8,7 @@ using Avalonia.Controls; using Avalonia.Data.Converters; using Avalonia.Media.Imaging; -namespace Avalonia.Themes.Default +namespace Avalonia.Themes.Simple { internal class IBitmapToImageConverter : IValueConverter { diff --git a/src/Avalonia.Themes.Default/InverseBooleanValueConverter.cs b/src/Avalonia.Themes.Simple/InverseBooleanValueConverter.cs similarity index 94% rename from src/Avalonia.Themes.Default/InverseBooleanValueConverter.cs rename to src/Avalonia.Themes.Simple/InverseBooleanValueConverter.cs index 7befc81b8e..15cc5b4a80 100644 --- a/src/Avalonia.Themes.Default/InverseBooleanValueConverter.cs +++ b/src/Avalonia.Themes.Simple/InverseBooleanValueConverter.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; using Avalonia.Data.Converters; -namespace Avalonia.Themes.Default +namespace Avalonia.Themes.Simple { class InverseBooleanValueConverter : IValueConverter { diff --git a/src/Avalonia.Themes.Simple/Properties/AssemblyInfo.cs b/src/Avalonia.Themes.Simple/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..f00510816a --- /dev/null +++ b/src/Avalonia.Themes.Simple/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using Avalonia.Metadata; + +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Themes.Simple")] diff --git a/src/Avalonia.Themes.Default/SimpleTheme.cs b/src/Avalonia.Themes.Simple/SimpleTheme.cs similarity index 89% rename from src/Avalonia.Themes.Default/SimpleTheme.cs rename to src/Avalonia.Themes.Simple/SimpleTheme.cs index 98e35355c8..f225cb4c4d 100644 --- a/src/Avalonia.Themes.Default/SimpleTheme.cs +++ b/src/Avalonia.Themes.Simple/SimpleTheme.cs @@ -6,7 +6,7 @@ using Avalonia.Markup.Xaml.Styling; using Avalonia.Styling; #nullable enable -namespace Avalonia.Themes.Default +namespace Avalonia.Themes.Simple { public class SimpleTheme : AvaloniaObject, IStyle, IResourceProvider { @@ -23,9 +23,9 @@ namespace Avalonia.Themes.Default /// Initializes a new instance of the class. /// /// The base URL for the XAML context. - public SimpleTheme(Uri baseUri) + public SimpleTheme(Uri? baseUri = null) { - _baseUri = baseUri; + _baseUri = baseUri ?? new Uri("avares://Avalonia.Themes.Simple/"); InitStyles(_baseUri); } @@ -138,18 +138,18 @@ namespace Avalonia.Themes.Default { new StyleInclude(baseUri) { - Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml") + Source = new Uri("avares://Avalonia.Themes.Simple/Controls/SimpleControls.xaml") }, new StyleInclude(baseUri) { - Source = new Uri("avares://Avalonia.Themes.Default/Accents/Base.xaml") + Source = new Uri("avares://Avalonia.Themes.Simple/Accents/Base.xaml") } }; _simpleLight = new Styles { new StyleInclude(baseUri) { - Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseLight.xaml") + Source = new Uri("avares://Avalonia.Themes.Simple/Accents/BaseLight.xaml") } }; @@ -157,7 +157,7 @@ namespace Avalonia.Themes.Default { new StyleInclude(baseUri) { - Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseDark.xaml") + Source = new Uri("avares://Avalonia.Themes.Simple/Accents/BaseDark.xaml") } }; } diff --git a/src/Avalonia.Themes.Default/SimpleThemeMode.cs b/src/Avalonia.Themes.Simple/SimpleThemeMode.cs similarity index 67% rename from src/Avalonia.Themes.Default/SimpleThemeMode.cs rename to src/Avalonia.Themes.Simple/SimpleThemeMode.cs index be33466327..683c751f10 100644 --- a/src/Avalonia.Themes.Default/SimpleThemeMode.cs +++ b/src/Avalonia.Themes.Simple/SimpleThemeMode.cs @@ -1,4 +1,4 @@ -namespace Avalonia.Themes.Default +namespace Avalonia.Themes.Simple { public enum SimpleThemeMode { diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 7043c60ae7..cc9737668d 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -277,7 +277,8 @@ namespace Avalonia // and sometimes attempts to use GLX might cause a segfault "llvmpipe" }; - public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name ?? "AvaloniaApplication"; + + public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name; /// /// Enables multitouch support. The default value is true. diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 009ccb6159..7b34705b3b 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -168,8 +168,7 @@ namespace Avalonia.X11 XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_WINDOW_TYPE, _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, new[] {_x11.Atoms._NET_WM_WINDOW_TYPE_NORMAL}, 1); - if (platform.Options.WmClass != null) - SetWmClass(platform.Options.WmClass); + SetWmClass(_platform.Options.WmClass); var surfaces = new List { @@ -1082,12 +1081,24 @@ namespace Avalonia.X11 public void SetWmClass(string wmClass) { - var data = Encoding.ASCII.GetBytes(wmClass); - fixed (void* pdata = data) + // See https://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS + // We don't actually parse the application's command line, so we only use RESOURCE_NAME and argv[0] + var appId = Environment.GetEnvironmentVariable("RESOURCE_NAME") + ?? Process.GetCurrentProcess().ProcessName; + + var encodedAppId = Encoding.ASCII.GetBytes(appId); + var encodedWmClass = Encoding.ASCII.GetBytes(wmClass ?? appId); + + var hint = XAllocClassHint(); + fixed(byte* pAppId = encodedAppId) + fixed (byte* pWmClass = encodedWmClass) { - XChangeProperty(_x11.Display, _handle, _x11.Atoms.XA_WM_CLASS, _x11.Atoms.XA_STRING, 8, - PropertyMode.Replace, pdata, data.Length); + hint->res_name = pAppId; + hint->res_class = pWmClass; + XSetClassHint(_x11.Display, _handle, hint); } + + XFree(hint); } public void SetMinMaxSize(Size minSize, Size maxSize) diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 464ec4f1c8..753d5f530c 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -109,6 +109,9 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern int XFree(IntPtr data); + + [DllImport(libX11)] + public static extern int XFree(void* data); [DllImport(libX11)] public static extern int XRaiseWindow(IntPtr display, IntPtr window); @@ -628,6 +631,12 @@ namespace Avalonia.X11 return XISelectEvents(display, window, emasks, devices.Count); } + + [DllImport(libX11)] + public static extern XClassHint* XAllocClassHint(); + + [DllImport(libX11)] + public static extern int XSetClassHint(IntPtr display, IntPtr window, XClassHint* class_hints); public struct XGeometry { @@ -639,6 +648,11 @@ namespace Avalonia.X11 public int bw; public int d; } + public struct XClassHint + { + public byte* res_name; + public byte* res_class; + } public struct XSyncValue { public int Hi; diff --git a/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs new file mode 100644 index 0000000000..e92ad02c7a --- /dev/null +++ b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs @@ -0,0 +1,27 @@ +using Avalonia.LinuxFramebuffer.Output; +using Avalonia.Media; +using JetBrains.Annotations; + +namespace Avalonia.LinuxFramebuffer +{ + public class DrmOutputOptions + { + /// + /// Scaling factor. + /// Default: 1.0 + /// + public double Scaling { get; set; } = 1.0; + + /// + /// If true an two cycle buffer swapping is processed at init. + /// Default: True + /// + public bool EnableInitialBufferSwapping { get; set; } = true; + + /// + /// Color for + /// Default: R0 G0 B0 A0 + /// + public Color InitialBufferSwappingColor { get; set; } = new Color(0, 0, 0, 0); + } +} diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index 4add4c423b..a642766809 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -140,6 +140,8 @@ public static class LinuxFramebufferPlatformExtensions public static int StartLinuxDrm(this T builder, string[] args, string card = null, double scaling = 1) where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card) {Scaling = scaling}); + public static int StartLinuxDrm(this T builder, string[] args, string card = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null) + where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options)); public static int StartLinuxDirect(this T builder, string[] args, IOutputBackend backend) where T : AppBuilderBase, new() diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs index 9c476b1b63..04bc2c1f67 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs @@ -162,6 +162,8 @@ namespace Avalonia.LinuxFramebuffer.Output [DllImport(libdrm, SetLastError = true)] public static extern drmModeConnector* drmModeGetConnector(int fd, uint connector); [DllImport(libdrm, SetLastError = true)] + public static extern drmModeConnector* drmModeGetConnectorCurrent(int fd, uint connector); + [DllImport(libdrm, SetLastError = true)] public static extern void drmModeFreeConnector(drmModeConnector* res); [DllImport(libdrm, SetLastError = true)] diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs index de281245f1..070e1a95bc 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs @@ -84,7 +84,7 @@ namespace Avalonia.LinuxFramebuffer.Output { public List Connectors { get; }= new List(); internal Dictionary Encoders { get; } = new Dictionary(); - public DrmResources(int fd) + public DrmResources(int fd, bool connectorsForceProbe = false) { var res = drmModeGetResources(fd); if (res == null) @@ -107,7 +107,7 @@ namespace Avalonia.LinuxFramebuffer.Output for (var c = 0; c < res->count_connectors; c++) { - var conn = drmModeGetConnector(fd, res->connectors[c]); + var conn = connectorsForceProbe ? drmModeGetConnector(fd, res->connectors[c]) : drmModeGetConnectorCurrent(fd, res->connectors[c]); Connectors.Add(new DrmConnector(conn)); drmModeFreeConnector(conn); } @@ -168,7 +168,7 @@ namespace Avalonia.LinuxFramebuffer.Output } } - public DrmResources GetResources() => new DrmResources(Fd); + public DrmResources GetResources(bool connectorsForceProbe = false) => new DrmResources(Fd, connectorsForceProbe); public void Dispose() { close(Fd); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs index 99c4b62716..ce210019c0 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs @@ -7,6 +7,7 @@ using Avalonia.OpenGL; using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Surfaces; using Avalonia.Platform.Interop; +using JetBrains.Annotations; using static Avalonia.LinuxFramebuffer.NativeUnsafeMethods; using static Avalonia.LinuxFramebuffer.Output.LibDrm; using static Avalonia.LinuxFramebuffer.Output.LibDrm.GbmColorFormats; @@ -15,20 +16,35 @@ namespace Avalonia.LinuxFramebuffer.Output { public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface { + private DrmOutputOptions _outputOptions = new(); private DrmCard _card; public PixelSize PixelSize => _mode.Resolution; - public double Scaling { get; set; } + + public double Scaling + { + get => _outputOptions.Scaling; + set => _outputOptions.Scaling = value; + } public IGlContext PrimaryContext => _deferredContext; private EglPlatformOpenGlInterface _platformGl; public IPlatformOpenGlInterface PlatformOpenGlInterface => _platformGl; - public DrmOutput(string path = null) + public DrmOutput(DrmCard card, DrmResources resources, DrmConnector connector, DrmModeInfo modeInfo, + DrmOutputOptions? options = null) { + if(options != null) + _outputOptions = options; + Init(card, resources, connector, modeInfo); + } + public DrmOutput(string path = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null) + { + if(options != null) + _outputOptions = options; + var card = new DrmCard(path); - var resources = card.GetResources(); - + var resources = card.GetResources(connectorsForceProbe); var connector = resources.Connectors.FirstOrDefault(x => x.Connection == DrmModeConnection.DRM_MODE_CONNECTED); @@ -142,9 +158,14 @@ namespace Avalonia.LinuxFramebuffer.Output _deferredContext = _platformGl.PrimaryEglContext; + var initialBufferSwappingColorR = _outputOptions.InitialBufferSwappingColor.R / 255.0f; + var initialBufferSwappingColorG = _outputOptions.InitialBufferSwappingColor.G / 255.0f; + var initialBufferSwappingColorB = _outputOptions.InitialBufferSwappingColor.B / 255.0f; + var initialBufferSwappingColorA = _outputOptions.InitialBufferSwappingColor.A / 255.0f; using (_deferredContext.MakeCurrent(_eglSurface)) { - _deferredContext.GlInterface.ClearColor(0, 0, 0, 0); + _deferredContext.GlInterface.ClearColor(initialBufferSwappingColorR, initialBufferSwappingColorG, + initialBufferSwappingColorB, initialBufferSwappingColorA); _deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); _eglSurface.SwapBuffers(); } @@ -162,13 +183,17 @@ namespace Avalonia.LinuxFramebuffer.Output _mode = mode; _currentBo = bo; - // Go trough two cycles of buffer swapping (there are render artifacts otherwise) - for(var c=0;c<2;c++) - using (CreateGlRenderTarget().BeginDraw()) - { - _deferredContext.GlInterface.ClearColor(0, 0, 0, 0); - _deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); - } + if (_outputOptions.EnableInitialBufferSwapping) + { + //Go trough two cycles of buffer swapping (there are render artifacts otherwise) + for(var c=0;c<2;c++) + using (CreateGlRenderTarget().BeginDraw()) + { + _deferredContext.GlInterface.ClearColor(initialBufferSwappingColorR, initialBufferSwappingColorG, + initialBufferSwappingColorB, initialBufferSwappingColorA); + _deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); + } + } } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index 094cd59025..f325e6e2d6 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -60,6 +60,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions InsertAfter( new XDataTypeTransformer()); + InsertBefore( + new AvaloniaXamlIlDeferredResourceTransformer() + ); + // After everything else InsertBefore( new AddNameScopeRegistration(), diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs new file mode 100644 index 0000000000..662263e513 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using System.Linq; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers +{ + internal class AvaloniaXamlIlDeferredResourceTransformer : IXamlAstTransformer + { + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) + { + if (!(node is XamlPropertyAssignmentNode pa) || pa.Values.Count != 2) + return node; + + if (!ShouldBeDeferred(pa.Values[1])) + return node; + + var types = context.GetAvaloniaTypes(); + + if (pa.Property.DeclaringType == types.ResourceDictionary && pa.Property.Name == "Content") + { + pa.Values[1] = new XamlDeferredContentNode(pa.Values[1], types.XamlIlTypes.Object, context.Configuration); + pa.PossibleSetters = new List + { + new XamlDirectCallPropertySetter(types.ResourceDictionaryDeferredAdd), + }; + } + else if (pa.Property.Name == "Resources" && pa.Property.Getter.ReturnType.Equals(types.IResourceDictionary)) + { + pa.Values[1] = new XamlDeferredContentNode(pa.Values[1], types.XamlIlTypes.Object, context.Configuration); + pa.PossibleSetters = new List + { + new AdderSetter(pa.Property.Getter, types.ResourceDictionaryDeferredAdd), + }; + } + + return node; + } + + private static bool ShouldBeDeferred(IXamlAstValueNode node) + { + // XAML compiler is currently strict about value types, allowing them to be created only through converters. + // At the moment it should be safe to not defer structs. + return !node.Type.GetClrType().IsValueType; + } + + class AdderSetter : IXamlPropertySetter, IXamlEmitablePropertySetter + { + private readonly IXamlMethod _getter; + private readonly IXamlMethod _adder; + + public AdderSetter(IXamlMethod getter, IXamlMethod adder) + { + _getter = getter; + _adder = adder; + TargetType = getter.DeclaringType; + Parameters = adder.ParametersWithThis().Skip(1).ToList(); + } + + public IXamlType TargetType { get; } + + public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters + { + AllowMultiple = true + }; + + public IReadOnlyList Parameters { get; } + public void Emit(IXamlILEmitter emitter) + { + var locals = new Stack(); + // Save all "setter" parameters + for (var c = Parameters.Count - 1; c >= 0; c--) + { + var loc = emitter.LocalsPool.GetLocal(Parameters[c]); + locals.Push(loc); + emitter.Stloc(loc.Local); + } + + emitter.EmitCall(_getter); + while (locals.Count > 0) + using (var loc = locals.Pop()) + emitter.Ldloc(loc.Local); + emitter.EmitCall(_adder, true); + } + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index 9d9f6a08ab..dbfbe0e070 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -98,6 +98,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlType TextDecorations { get; } public IXamlType TextTrimming { get; } public IXamlType ISetter { get; } + public IXamlType IResourceDictionary { get; } + public IXamlType ResourceDictionary { get; } + public IXamlMethod ResourceDictionaryDeferredAdd { get; } public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg) { @@ -218,6 +221,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers TextDecorations = cfg.TypeSystem.GetType("Avalonia.Media.TextDecorations"); TextTrimming = cfg.TypeSystem.GetType("Avalonia.Media.TextTrimming"); ISetter = cfg.TypeSystem.GetType("Avalonia.Styling.ISetter"); + IResourceDictionary = cfg.TypeSystem.GetType("Avalonia.Controls.IResourceDictionary"); + ResourceDictionary = cfg.TypeSystem.GetType("Avalonia.Controls.ResourceDictionary"); + ResourceDictionaryDeferredAdd = ResourceDictionary.FindMethod("AddDeferred", XamlIlTypes.Void, true, XamlIlTypes.Object, + cfg.TypeSystem.GetType("System.Func`2").MakeGenericType( + cfg.TypeSystem.GetType("System.IServiceProvider"), + XamlIlTypes.Object)); } } diff --git a/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs b/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs index 265af3c5da..4a3538fff2 100644 --- a/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs @@ -19,6 +19,7 @@ namespace Avalonia.Data private bool _isSetterValue; private IStyledElement _target = default!; private Type? _targetType; + private bool _hasProducedValue; public TemplateBinding() { @@ -143,10 +144,12 @@ namespace Avalonia.Data } PublishNext(value); + _hasProducedValue = true; } - else + else if (_hasProducedValue) { PublishNext(AvaloniaProperty.UnsetValue); + _hasProducedValue = false; } } diff --git a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs index 5628ae177c..6400d67fde 100644 --- a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs +++ b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs @@ -1,11 +1,8 @@ using System; using System.IO; -using System.Runtime.CompilerServices; -using System.Security.Cryptography; using Avalonia.Media.Imaging; using Avalonia.Platform; using Avalonia.Skia.Helpers; -using Avalonia.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia @@ -57,7 +54,8 @@ namespace Avalonia.Skia public ImmutableBitmap(Stream stream, int decodeSize, bool horizontal, BitmapInterpolationMode interpolationMode) { using (var skStream = new SKManagedStream(stream)) - using (var codec = SKCodec.Create(skStream)) + using (var skData = SKData.Create(skStream)) + using (var codec = SKCodec.Create(skData)) { var info = codec.Info; diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index 506edf0627..80bfcc5973 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -4,7 +4,6 @@ using System.Threading; using Avalonia.Media.Imaging; using Avalonia.Platform; using Avalonia.Skia.Helpers; -using Avalonia.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia @@ -25,8 +24,9 @@ namespace Avalonia.Skia public WriteableBitmapImpl(Stream stream) { using (var skiaStream = new SKManagedStream(stream)) + using (var skData = SKData.Create(skiaStream)) { - _bitmap = SKBitmap.Decode(skiaStream); + _bitmap = SKBitmap.Decode(skData); if (_bitmap == null) { @@ -41,7 +41,8 @@ namespace Avalonia.Skia public WriteableBitmapImpl(Stream stream, int decodeSize, bool horizontal, BitmapInterpolationMode interpolationMode) { using (var skStream = new SKManagedStream(stream)) - using (var codec = SKCodec.Create(skStream)) + using (var skData = SKData.Create(skStream)) + using (var codec = SKCodec.Create(skData)) { var info = codec.Info; diff --git a/src/Web/Avalonia.Web.Blazor/Interop/Storage/StorageProviderInterop.cs b/src/Web/Avalonia.Web.Blazor/Interop/Storage/StorageProviderInterop.cs index 14dc53d7b5..2bc46e97b5 100644 --- a/src/Web/Avalonia.Web.Blazor/Interop/Storage/StorageProviderInterop.cs +++ b/src/Web/Avalonia.Web.Blazor/Interop/Storage/StorageProviderInterop.cs @@ -145,7 +145,7 @@ namespace Avalonia.Web.Blazor.Interop.Storage public bool CanBookmark => true; - public Task SaveBookmark() + public Task SaveBookmarkAsync() { return FileHandle.InvokeAsync("saveBookmark").AsTask(); } @@ -155,7 +155,7 @@ namespace Avalonia.Web.Blazor.Interop.Storage return Task.FromResult(null); } - public Task ReleaseBookmark() + public Task ReleaseBookmarkAsync() { return FileHandle.InvokeAsync("deleteBookmark").AsTask(); } @@ -174,7 +174,7 @@ namespace Avalonia.Web.Blazor.Interop.Storage } public bool CanOpenRead => true; - public async Task OpenRead() + public async Task OpenReadAsync() { var stream = await FileHandle.InvokeAsync("openRead"); // Remove maxAllowedSize limit, as developer can decide if they read only small part or everything. @@ -182,7 +182,7 @@ namespace Avalonia.Web.Blazor.Interop.Storage } public bool CanOpenWrite => true; - public async Task OpenWrite() + public async Task OpenWriteAsync() { var properties = await FileHandle.InvokeAsync("getProperties"); var streamWriter = await FileHandle.InvokeAsync("openWrite"); @@ -196,5 +196,30 @@ namespace Avalonia.Web.Blazor.Interop.Storage public JSStorageFolder(IJSInProcessObjectReference fileHandle) : base(fileHandle) { } + + public async Task> GetItemsAsync() + { + var items = await FileHandle.InvokeAsync("getItems"); + if (items is null) + { + return Array.Empty(); + } + + var count = items.Invoke("count"); + + return Enumerable.Range(0, count) + .Select(index => + { + var reference = items.Invoke("at", index); + return reference.Invoke("getKind") switch + { + "directory" => (IStorageItem)new JSStorageFolder(reference), + "file" => new JSStorageFile(reference), + _ => null + }; + }) + .Where(i => i is not null) + .ToArray()!; + } } } diff --git a/src/Web/Avalonia.Web.Blazor/Interop/Typescript/StorageProvider.ts b/src/Web/Avalonia.Web.Blazor/Interop/Typescript/StorageProvider.ts index c32eef3226..aee74b9067 100644 --- a/src/Web/Avalonia.Web.Blazor/Interop/Typescript/StorageProvider.ts +++ b/src/Web/Avalonia.Web.Blazor/Interop/Typescript/StorageProvider.ts @@ -14,6 +14,8 @@ declare global { queryPermission(options?: { mode: PermissionsMode }): Promise<"granted" | "denied" | "prompt">; requestPermission(options?: { mode: PermissionsMode }): Promise<"granted" | "denied" | "prompt">; + + entries(): AsyncIterableIterator<[string, FileSystemFileHandle]>; } type WellKnownDirectory = "desktop" | "documents" | "downloads" | "music" | "pictures" | "videos"; type StartInDirectory = WellKnownDirectory | FileSystemFileHandle; @@ -53,7 +55,7 @@ class IndexedDbWrapper { } public connect(): Promise { - var conn = window.indexedDB.open(this.databaseName, 1); + const conn = window.indexedDB.open(this.databaseName, 1); conn.onupgradeneeded = event => { const db = (>event.target).result; @@ -85,7 +87,7 @@ class InnerDbConnection { const os = this.openStore(store, "readwrite"); return new Promise((resolve, reject) => { - var response = os.put(obj, key); + const response = os.put(obj, key); response.onsuccess = () => { resolve(response.result); }; @@ -99,7 +101,7 @@ class InnerDbConnection { const os = this.openStore(store, "readonly"); return new Promise((resolve, reject) => { - var response = os.get(key); + const response = os.get(key); response.onsuccess = () => { resolve(response.result); }; @@ -113,7 +115,7 @@ class InnerDbConnection { const os = this.openStore(store, "readwrite"); return new Promise((resolve, reject) => { - var response = os.delete(key); + const response = os.delete(key); response.onsuccess = () => { resolve(); }; @@ -134,17 +136,20 @@ const avaloniaDb = new IndexedDbWrapper("AvaloniaDb", [ ]) class StorageItem { - constructor(private handle: FileSystemFileHandle, private bookmarkId?: string) { } + constructor(public handle: FileSystemFileHandle, private bookmarkId?: string) { } public getName(): string { return this.handle.name } + public getKind(): string { + return this.handle.kind; + } + public async openRead(): Promise { await this.verityPermissions('read'); - var file = await this.handle.getFile(); - return file; + return await this.handle.getFile(); } public async openWrite(): Promise { @@ -154,7 +159,7 @@ class StorageItem { } public async getProperties(): Promise<{ Size: number, LastModified: number, Type: string }> { - var file = this.handle.getFile && await this.handle.getFile(); + const file = this.handle.getFile && await this.handle.getFile(); return file && { Size: file.size, @@ -163,6 +168,18 @@ class StorageItem { } } + public async getItems(): Promise { + if (this.handle.kind !== "directory"){ + return new StorageItems([]); + } + + const items: StorageItem[] = []; + for await (const [key, value] of this.handle.entries()) { + items.push(new StorageItem(value)); + } + return new StorageItems(items); + } + private async verityPermissions(mode: PermissionsMode): Promise { if (await this.handle.queryPermission({ mode }) === 'granted') { return; @@ -235,12 +252,12 @@ export class StorageProvider { } public static async selectFolderDialog( - startIn: StartInDirectory | null) + startIn: StorageItem | null) : Promise { // 'Picker' API doesn't accept "null" as a parameter, so it should be set to undefined. const options: DirectoryPickerOptions = { - startIn: (startIn || undefined) + startIn: (startIn?.handle || undefined) }; const handle = await window.showDirectoryPicker(options); @@ -248,12 +265,12 @@ export class StorageProvider { } public static async openFileDialog( - startIn: StartInDirectory | null, multiple: boolean, + startIn: StorageItem | null, multiple: boolean, types: FilePickerAcceptType[] | null, excludeAcceptAllOption: boolean) : Promise { const options: OpenFilePickerOptions = { - startIn: (startIn || undefined), + startIn: (startIn?.handle || undefined), multiple, excludeAcceptAllOption, types: (types || undefined) @@ -264,12 +281,12 @@ export class StorageProvider { } public static async saveFileDialog( - startIn: StartInDirectory | null, suggestedName: string | null, + startIn: StorageItem | null, suggestedName: string | null, types: FilePickerAcceptType[] | null, excludeAcceptAllOption: boolean) : Promise { const options: SaveFilePickerOptions = { - startIn: (startIn || undefined), + startIn: (startIn?.handle || undefined), suggestedName: (suggestedName || undefined), excludeAcceptAllOption, types: (types || undefined) diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 7f1af46e97..81fa8c4bce 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using Avalonia.Controls; @@ -9,7 +8,6 @@ using Avalonia.Direct2D1.Media.Imaging; using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform; -using Avalonia.Media.Imaging; using SharpDX.DirectWrite; using GlyphRun = Avalonia.Media.GlyphRun; using TextAlignment = Avalonia.Media.TextAlignment; diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs index 5334b90d62..84c3cc5c51 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs @@ -120,16 +120,14 @@ namespace Avalonia.Win32.WinRT.Composition private void RunLoop() { + using (var act = _compositor5.RequestCommitAsync()) + act.SetCompleted(new RunLoopHandler(this)); + + while (true) { - var st = Stopwatch.StartNew(); - using (var act = _compositor5.RequestCommitAsync()) - act.SetCompleted(new RunLoopHandler(this)); - while (true) - { - UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0); - lock (_pumpLock) - UnmanagedMethods.DispatchMessage(ref msg); - } + UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0); + lock (_pumpLock) + UnmanagedMethods.DispatchMessage(ref msg); } } diff --git a/src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs b/src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs index 6fb296d0e0..a801e83562 100644 --- a/src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs +++ b/src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Linq; using System.Threading.Tasks; using Avalonia.Logging; using Avalonia.Platform.Storage; @@ -49,13 +51,13 @@ internal abstract class IOSStorageItem : IStorageBookmarkItem return Task.FromResult(new IOSStorageFolder(Url.RemoveLastPathComponent())); } - public Task ReleaseBookmark() + public Task ReleaseBookmarkAsync() { // no-op return Task.CompletedTask; } - public Task SaveBookmark() + public Task SaveBookmarkAsync() { try { @@ -102,12 +104,12 @@ internal sealed class IOSStorageFile : IOSStorageItem, IStorageBookmarkFile public bool CanOpenWrite => true; - public Task OpenRead() + public Task OpenReadAsync() { return Task.FromResult(new IOSSecurityScopedStream(Url, FileAccess.Read)); } - public Task OpenWrite() + public Task OpenWriteAsync() { return Task.FromResult(new IOSSecurityScopedStream(Url, FileAccess.Write)); } @@ -118,4 +120,19 @@ internal sealed class IOSStorageFolder : IOSStorageItem, IStorageBookmarkFolder public IOSStorageFolder(NSUrl url) : base(url) { } + + public Task> GetItemsAsync() + { + var content = NSFileManager.DefaultManager.GetDirectoryContent(Url, null, NSDirectoryEnumerationOptions.None, out var error); + if (error is not null) + { + return Task.FromException>(new NSErrorException(error)); + } + + var items = content + .Select(u => u.HasDirectoryPath ? (IStorageItem)new IOSStorageFolder(u) : new IOSStorageFile(u)) + .ToArray(); + + return Task.FromResult>(items); + } } diff --git a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj index 1cf68c1605..f509bb21ba 100644 --- a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj +++ b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs b/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs index 7ad40f68e4..9455f5fac2 100644 --- a/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs +++ b/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs @@ -8,6 +8,8 @@ namespace Avalonia.SourceGenerator.CompositionGenerator using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Expressions; +// Special license applies License.md + namespace Avalonia.Rendering.Composition {{ "; @@ -56,4 +58,4 @@ namespace Avalonia.Rendering.Composition _output.AddSource("CompositionAnimations.cs", code); } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs index 705c8fad9c..02012bf62b 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs +++ b/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs @@ -408,10 +408,34 @@ public class CompositorHitTestingTests : CompositorTestsBase s.AssertHitTest(175, 100, null); } } + + [Fact] + public void HitTest_Should_Not_Hit_Controls_Next_Pixel() + { + using (var s = new CompositorServices(new Size(200, 200))) + { + Border targetRectangle; + + var stackPanel = new StackPanel + { + Orientation = Orientation.Vertical, + HorizontalAlignment = HorizontalAlignment.Left, + Children = + { + new Border { Width = 10, Height = 10, Background= Brushes.Red}, + { targetRectangle = new Border { Width = 10, Height = 10, Background = Brushes.Green} } + } + }; + + s.TopLevel.Content = stackPanel; + + s.AssertHitTest(new Point(5, 10), null, targetRectangle); + } + } private IDisposable TestApplication() { return UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs b/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs index 33c7b3e0f8..d3fdbb63db 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs +++ b/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs @@ -537,6 +537,38 @@ namespace Avalonia.Base.UnitTests.Rendering } } + [Fact] + public void HitTest_Should_Not_Hit_Controls_Next_Pixel() + { + using (TestApplication()) + { + Border targetRectangle; + + var root = new TestRoot + { + Width = 50, + Height = 200, + Child = new StackPanel + { + Orientation = Orientation.Vertical, + HorizontalAlignment = HorizontalAlignment.Left, + Children = + { + new Border { Width = 50, Height = 50, Background = Brushes.Red}, + { targetRectangle = new Border { Width = 50, Height = 50, Background = Brushes.Green} } + } + } + }; + + root.Renderer = new DeferredRenderer(root, null); + root.Measure(Size.Infinity); + root.Arrange(new Rect(root.DesiredSize)); + + var result = root.Renderer.HitTest(new Point(25, 50), root, null); + Assert.Equal(new[] { targetRectangle }, result); + } + } + private IDisposable TestApplication() { return UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); diff --git a/tests/Avalonia.Base.UnitTests/Utilities/UriExtensionsTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/UriExtensionsTests.cs index 5c3ac6adeb..4a879c8ced 100644 --- a/tests/Avalonia.Base.UnitTests/Utilities/UriExtensionsTests.cs +++ b/tests/Avalonia.Base.UnitTests/Utilities/UriExtensionsTests.cs @@ -10,9 +10,9 @@ public class UriExtensionsTests public void Assembly_Name_From_Query_Parsed() { const string key = "assembly"; - const string value = "Avalonia.Themes.Default"; + const string value = "Avalonia.Themes.Simple"; - var uri = new Uri($"resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?{key}={value}"); + var uri = new Uri($"resm:Avalonia.Themes.Simple.Accents.BaseLight.xaml?{key}={value}"); var name = uri.GetAssemblyNameFromQuery(); Assert.Equal(value, name); @@ -21,7 +21,7 @@ public class UriExtensionsTests [Fact] public void Assembly_Name_From_Empty_Query_Not_Parsed() { - var uri = new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml"); + var uri = new Uri("resm:Avalonia.Themes.Simple.Accents.BaseLight.xaml"); var name = uri.GetAssemblyNameFromQuery(); Assert.Equal(string.Empty, name); diff --git a/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj b/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj index 5d17808e0c..3f4978f544 100644 --- a/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj +++ b/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj @@ -9,7 +9,7 @@ - + diff --git a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs index 9a5b49790d..86ba4c6005 100644 --- a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs +++ b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs @@ -4,6 +4,8 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml.Styling; using Avalonia.Platform; using Avalonia.Styling; +using Avalonia.Themes.Fluent; +using Avalonia.Themes.Simple; using Avalonia.UnitTests; using BenchmarkDotNet.Attributes; @@ -25,32 +27,25 @@ namespace Avalonia.Benchmarks.Themes } [Benchmark] - [Arguments("avares://Avalonia.Themes.Fluent/FluentDark.xaml")] - [Arguments("avares://Avalonia.Themes.Fluent/FluentLight.xaml")] - public bool InitFluentTheme(string themeUri) + [Arguments(FluentThemeMode.Dark)] + [Arguments(FluentThemeMode.Light)] + public bool InitFluentTheme(FluentThemeMode mode) { - UnitTestApplication.Current.Styles[0] = new StyleInclude(new Uri("resm:Styles?assembly=Avalonia.Benchmarks")) + UnitTestApplication.Current.Styles[0] = new FluentTheme(new Uri("resm:Styles?assembly=Avalonia.Benchmarks")) { - Source = new Uri(themeUri) + Mode = mode }; return ((IResourceHost)UnitTestApplication.Current).TryGetResource("SystemAccentColor", out _); } [Benchmark] - [Arguments("avares://Avalonia.Themes.Default/Accents/BaseLight.xaml")] - [Arguments("avares://Avalonia.Themes.Default/Accents/BaseDark.xaml")] - public bool InitDefaultTheme(string themeUri) + [Arguments(SimpleThemeMode.Dark)] + [Arguments(SimpleThemeMode.Light)] + public bool InitSimpleTheme(SimpleThemeMode mode) { - UnitTestApplication.Current.Styles[0] = new Styles + UnitTestApplication.Current.Styles[0] = new SimpleTheme(new Uri("resm:Styles?assembly=Avalonia.Benchmarks")) { - new StyleInclude(new Uri("resm:Styles?assembly=Avalonia.Benchmarks")) - { - Source = new Uri(themeUri) - }, - new StyleInclude(new Uri("resm:Styles?assembly=Avalonia.Benchmarks")) - { - Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml") - } + Mode = mode }; return ((IResourceHost)UnitTestApplication.Current).TryGetResource("ThemeAccentColor", out _); } diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index afa153a593..f6d96edb99 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -9,7 +9,6 @@ using Avalonia.Data; using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Styling; -using Avalonia.Threading; using Avalonia.UnitTests; using Avalonia.VisualTree; using Xunit; @@ -19,7 +18,7 @@ namespace Avalonia.Controls.UnitTests public class ListBoxTests { private MouseTestHelper _mouse = new MouseTestHelper(); - + [Fact] public void Should_Use_ItemTemplate_To_Create_Item_Content() { @@ -433,6 +432,47 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void ListBox_Should_Be_Valid_After_Remove_Of_Item_In_NonVisibleArea() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var items = new AvaloniaList(Enumerable.Range(1, 30).Select(v => v.ToString())); + + var wnd = new Window() { Width = 100, Height = 100, IsVisible = true }; + + var target = new ListBox() + { + AutoScrollToSelectedItem = true, + Height = 100, + Width = 50, + VirtualizationMode = ItemVirtualizationMode.Simple, + ItemTemplate = new FuncDataTemplate((c, _) => new Border() { Height = 10 }), + Items = items, + }; + wnd.Content = target; + + var lm = wnd.LayoutManager; + + lm.ExecuteInitialLayoutPass(); + + //select last / scroll to last item + target.SelectedItem = items.Last(); + + lm.ExecuteLayoutPass(); + + //remove the first item (in non realized area of the listbox) + items.Remove("1"); + lm.ExecuteLayoutPass(); + + Assert.Equal("30", target.ItemContainerGenerator.ContainerFromIndex(items.Count - 1).DataContext); + Assert.Equal("29", target.ItemContainerGenerator.ContainerFromIndex(items.Count - 2).DataContext); + Assert.Equal("28", target.ItemContainerGenerator.ContainerFromIndex(items.Count - 3).DataContext); + Assert.Equal("27", target.ItemContainerGenerator.ContainerFromIndex(items.Count - 4).DataContext); + Assert.Equal("26", target.ItemContainerGenerator.ContainerFromIndex(items.Count - 5).DataContext); + } + } + [Fact] public void Clicking_Item_Should_Raise_BringIntoView_For_Correct_Control() { @@ -656,7 +696,6 @@ namespace Avalonia.Controls.UnitTests public string Value { get; } } - [Fact] public void SelectedItem_Validation() { @@ -670,11 +709,11 @@ namespace Avalonia.Controls.UnitTests }; Prepare(target); - + var exception = new System.InvalidCastException("failed validation"); var textObservable = new BehaviorSubject(new BindingNotification(exception, BindingErrorType.DataValidationError)); target.Bind(ComboBox.SelectedItemProperty, textObservable); - + Assert.True(DataValidationErrors.GetHasErrors(target)); Assert.True(DataValidationErrors.GetErrors(target).SequenceEqual(new[] { exception })); } diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs index 8f795104bf..bf516748cc 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs @@ -5,10 +5,12 @@ using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.LogicalTree; using Avalonia.Styling; using Avalonia.UnitTests; using Avalonia.VisualTree; +using Moq; using Xunit; namespace Avalonia.Controls.UnitTests @@ -60,104 +62,123 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Clicking_Item_Should_Select_It() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = new FuncControlTemplate(CreateListBoxTemplate), - Items = new[] { "Foo", "Bar", "Baz " }, - }; - - ApplyTemplate(target); - _mouse.Click(target.Presenter.Panel.Children[0]); - - Assert.Equal(0, target.SelectedIndex); + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + ApplyTemplate(target); + _mouse.Click(target.Presenter.Panel.Children[0]); + + Assert.Equal(0, target.SelectedIndex); + } } [Fact] public void Clicking_Selected_Item_Should_Not_Deselect_It() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = new FuncControlTemplate(CreateListBoxTemplate), - Items = new[] { "Foo", "Bar", "Baz " }, - }; - - ApplyTemplate(target); - target.SelectedIndex = 0; + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + ApplyTemplate(target); + target.SelectedIndex = 0; - _mouse.Click(target.Presenter.Panel.Children[0]); + _mouse.Click(target.Presenter.Panel.Children[0]); - Assert.Equal(0, target.SelectedIndex); + Assert.Equal(0, target.SelectedIndex); + } } [Fact] public void Clicking_Item_Should_Select_It_When_SelectionMode_Toggle() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = new FuncControlTemplate(CreateListBoxTemplate), - Items = new[] { "Foo", "Bar", "Baz " }, - SelectionMode = SelectionMode.Single | SelectionMode.Toggle, - }; - - ApplyTemplate(target); + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Single | SelectionMode.Toggle, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + ApplyTemplate(target); - _mouse.Click(target.Presenter.Panel.Children[0]); + _mouse.Click(target.Presenter.Panel.Children[0]); - Assert.Equal(0, target.SelectedIndex); + Assert.Equal(0, target.SelectedIndex); + } } [Fact] public void Clicking_Selected_Item_Should_Deselect_It_When_SelectionMode_Toggle() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = new FuncControlTemplate(CreateListBoxTemplate), - Items = new[] { "Foo", "Bar", "Baz " }, - SelectionMode = SelectionMode.Toggle, - }; + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Toggle, + }; - ApplyTemplate(target); - target.SelectedIndex = 0; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + ApplyTemplate(target); + target.SelectedIndex = 0; - _mouse.Click(target.Presenter.Panel.Children[0]); + _mouse.Click(target.Presenter.Panel.Children[0]); - Assert.Equal(-1, target.SelectedIndex); + Assert.Equal(-1, target.SelectedIndex); + } } [Fact] public void Clicking_Selected_Item_Should_Not_Deselect_It_When_SelectionMode_ToggleAlwaysSelected() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = new FuncControlTemplate(CreateListBoxTemplate), - Items = new[] { "Foo", "Bar", "Baz " }, - SelectionMode = SelectionMode.Toggle | SelectionMode.AlwaysSelected, - }; - - ApplyTemplate(target); - target.SelectedIndex = 0; + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Toggle | SelectionMode.AlwaysSelected, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + ApplyTemplate(target); + target.SelectedIndex = 0; - _mouse.Click(target.Presenter.Panel.Children[0]); + _mouse.Click(target.Presenter.Panel.Children[0]); - Assert.Equal(0, target.SelectedIndex); + Assert.Equal(0, target.SelectedIndex); + } } [Fact] public void Clicking_Another_Item_Should_Select_It_When_SelectionMode_Toggle() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = new FuncControlTemplate(CreateListBoxTemplate), - Items = new[] { "Foo", "Bar", "Baz " }, - SelectionMode = SelectionMode.Single | SelectionMode.Toggle, - }; - - ApplyTemplate(target); - target.SelectedIndex = 1; + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Single | SelectionMode.Toggle, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + ApplyTemplate(target); + target.SelectedIndex = 1; - _mouse.Click(target.Presenter.Panel.Children[0]); + _mouse.Click(target.Presenter.Panel.Children[0]); - Assert.Equal(0, target.SelectedIndex); + Assert.Equal(0, target.SelectedIndex); + } } [Fact] diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index 4b6b6a1182..330cbfd7b9 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -14,6 +14,7 @@ using Avalonia.Controls.Selection; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.Interactivity; using Avalonia.Markup.Data; using Avalonia.Platform; @@ -1115,42 +1116,48 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Setting_SelectedItem_With_Pointer_Should_Set_TabOnceActiveElement() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz " }, - }; - - Prepare(target); - _helper.Down((Interactive)target.Presenter.Panel.Children[1]); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz " }, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + Prepare(target); + _helper.Down((Interactive)target.Presenter.Panel.Children[1]); - var panel = target.Presenter.Panel; + var panel = target.Presenter.Panel; - Assert.Equal( - KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel), - panel.Children[1]); + Assert.Equal( + KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel), + panel.Children[1]); + } } [Fact] public void Removing_SelectedItem_Should_Clear_TabOnceActiveElement() { - var items = new ObservableCollection(new[] { "Foo", "Bar", "Baz " }); - - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = items, - }; + var items = new ObservableCollection(new[] { "Foo", "Bar", "Baz " }); - Prepare(target); + var target = new ListBox + { + Template = Template(), + Items = items, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + Prepare(target); - _helper.Down(target.Presenter.Panel.Children[1]); + _helper.Down(target.Presenter.Panel.Children[1]); - items.RemoveAt(1); + items.RemoveAt(1); - var panel = target.Presenter.Panel; + var panel = target.Presenter.Panel; - Assert.Null(KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel)); + Assert.Null(KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel)); + } } [Fact] @@ -1230,31 +1237,37 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Should_Select_Correct_Item_When_Duplicate_Items_Are_Present() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, - }; - - Prepare(target); - _helper.Down((Interactive)target.Presenter.Panel.Children[3]); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + Prepare(target); + _helper.Down((Interactive)target.Presenter.Panel.Children[3]); - Assert.Equal(3, target.SelectedIndex); + Assert.Equal(3, target.SelectedIndex); + } } [Fact] public void Should_Apply_Selected_Pseudoclass_To_Correct_Item_When_Duplicate_Items_Are_Present() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, - }; - - Prepare(target); - _helper.Down((Interactive)target.Presenter.Panel.Children[3]); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + Prepare(target); + _helper.Down((Interactive)target.Presenter.Panel.Children[3]); - Assert.Equal(new[] { ":pressed", ":selected" }, target.Presenter.Panel.Children[3].Classes); + Assert.Equal(new[] { ":pressed", ":selected" }, target.Presenter.Panel.Children[3].Classes); + } } [Fact] diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs index 6b26d76371..5d2f4e2a64 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs @@ -10,8 +10,10 @@ using Avalonia.Controls.Selection; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.Interactivity; using Avalonia.UnitTests; +using Moq; using Xunit; namespace Avalonia.Controls.UnitTests.Primitives @@ -701,261 +703,290 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Shift_Selecting_From_No_Selection_Selects_From_Start() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift); - - var panel = target.Presenter.Panel; - - Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems); - Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target)); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift); + + var panel = target.Presenter.Panel; + + Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems); + Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target)); + } } [Fact] public void Ctrl_Selecting_Raises_SelectionChanged_Events() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Qux" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Qux" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); - SelectionChangedEventArgs receivedArgs = null; + SelectionChangedEventArgs receivedArgs = null; - target.SelectionChanged += (_, args) => receivedArgs = args; + target.SelectionChanged += (_, args) => receivedArgs = args; - void VerifyAdded(string selection) - { - Assert.NotNull(receivedArgs); - Assert.Equal(new[] { selection }, receivedArgs.AddedItems); - Assert.Empty(receivedArgs.RemovedItems); - } + void VerifyAdded(string selection) + { + Assert.NotNull(receivedArgs); + Assert.Equal(new[] { selection }, receivedArgs.AddedItems); + Assert.Empty(receivedArgs.RemovedItems); + } - void VerifyRemoved(string selection) - { - Assert.NotNull(receivedArgs); - Assert.Equal(new[] { selection }, receivedArgs.RemovedItems); - Assert.Empty(receivedArgs.AddedItems); - } + void VerifyRemoved(string selection) + { + Assert.NotNull(receivedArgs); + Assert.Equal(new[] { selection }, receivedArgs.RemovedItems); + Assert.Empty(receivedArgs.AddedItems); + } - _helper.Click((Interactive)target.Presenter.Panel.Children[1]); + _helper.Click((Interactive)target.Presenter.Panel.Children[1]); - VerifyAdded("Bar"); + VerifyAdded("Bar"); - receivedArgs = null; - _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); + receivedArgs = null; + _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); - VerifyAdded("Baz"); + VerifyAdded("Baz"); - receivedArgs = null; - _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); + receivedArgs = null; + _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); - VerifyAdded("Qux"); + VerifyAdded("Qux"); - receivedArgs = null; - _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Control); + receivedArgs = null; + _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Control); - VerifyRemoved("Bar"); + VerifyRemoved("Bar"); + } } [Fact] public void Ctrl_Selecting_SelectedItem_With_Multiple_Selection_Active_Sets_SelectedItem_To_Next_Selection() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Qux" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[1]); - _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); - _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); - - Assert.Equal(1, target.SelectedIndex); - Assert.Equal("Bar", target.SelectedItem); - Assert.Equal(new[] { "Bar", "Baz", "Qux" }, target.SelectedItems); - - _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Control); - - Assert.Equal(2, target.SelectedIndex); - Assert.Equal("Baz", target.SelectedItem); - Assert.Equal(new[] { "Baz", "Qux" }, target.SelectedItems); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Qux" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[1]); + _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); + _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); + + Assert.Equal(1, target.SelectedIndex); + Assert.Equal("Bar", target.SelectedItem); + Assert.Equal(new[] { "Bar", "Baz", "Qux" }, target.SelectedItems); + + _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Control); + + Assert.Equal(2, target.SelectedIndex); + Assert.Equal("Baz", target.SelectedItem); + Assert.Equal(new[] { "Baz", "Qux" }, target.SelectedItems); + } } [Fact] public void Ctrl_Selecting_Non_SelectedItem_With_Multiple_Selection_Active_Leaves_SelectedItem_The_Same() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - SelectionMode = SelectionMode.Multiple, - }; + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[1]); - _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[1]); + _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); - Assert.Equal(1, target.SelectedIndex); - Assert.Equal("Bar", target.SelectedItem); + Assert.Equal(1, target.SelectedIndex); + Assert.Equal("Bar", target.SelectedItem); - _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); + _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); - Assert.Equal(1, target.SelectedIndex); - Assert.Equal("Bar", target.SelectedItem); + Assert.Equal(1, target.SelectedIndex); + Assert.Equal("Bar", target.SelectedItem); + } } [Fact] public void Should_Ctrl_Select_Correct_Item_When_Duplicate_Items_Are_Present() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[3]); - _helper.Click((Interactive)target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control); - - var panel = target.Presenter.Panel; - - Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); - Assert.Equal(new[] { 3, 4 }, SelectedContainers(target)); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[3]); + _helper.Click((Interactive)target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control); + + var panel = target.Presenter.Panel; + + Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); + Assert.Equal(new[] { 3, 4 }, SelectedContainers(target)); + } } [Fact] public void Should_Shift_Select_Correct_Item_When_Duplicates_Are_Present() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[3]); - _helper.Click((Interactive)target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); - - var panel = target.Presenter.Panel; - - Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems); - Assert.Equal(new[] { 3, 4, 5 }, SelectedContainers(target)); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[3]); + _helper.Click((Interactive)target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); + + var panel = target.Presenter.Panel; + + Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems); + Assert.Equal(new[] { 3, 4, 5 }, SelectedContainers(target)); + } } [Fact] public void Can_Shift_Select_All_Items_When_Duplicates_Are_Present() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[0]); - _helper.Click((Interactive)target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); - - var panel = target.Presenter.Panel; - - Assert.Equal(new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, target.SelectedItems); - Assert.Equal(new[] { 0, 1, 2, 3, 4, 5 }, SelectedContainers(target)); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[0]); + _helper.Click((Interactive)target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); + + var panel = target.Presenter.Panel; + + Assert.Equal(new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, target.SelectedItems); + Assert.Equal(new[] { 0, 1, 2, 3, 4, 5 }, SelectedContainers(target)); + } } [Fact] public void Shift_Selecting_Raises_SelectionChanged_Events() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Qux" }, - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Qux" }, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); - SelectionChangedEventArgs receivedArgs = null; + SelectionChangedEventArgs receivedArgs = null; - target.SelectionChanged += (_, args) => receivedArgs = args; + target.SelectionChanged += (_, args) => receivedArgs = args; - void VerifyAdded(params string[] selection) - { - Assert.NotNull(receivedArgs); - Assert.Equal(selection, receivedArgs.AddedItems); - Assert.Empty(receivedArgs.RemovedItems); - } + void VerifyAdded(params string[] selection) + { + Assert.NotNull(receivedArgs); + Assert.Equal(selection, receivedArgs.AddedItems); + Assert.Empty(receivedArgs.RemovedItems); + } - void VerifyRemoved(string selection) - { - Assert.NotNull(receivedArgs); - Assert.Equal(new[] { selection }, receivedArgs.RemovedItems); - Assert.Empty(receivedArgs.AddedItems); - } + void VerifyRemoved(string selection) + { + Assert.NotNull(receivedArgs); + Assert.Equal(new[] { selection }, receivedArgs.RemovedItems); + Assert.Empty(receivedArgs.AddedItems); + } - _helper.Click((Interactive)target.Presenter.Panel.Children[1]); + _helper.Click((Interactive)target.Presenter.Panel.Children[1]); - VerifyAdded("Bar"); + VerifyAdded("Bar"); - receivedArgs = null; - _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Shift); + receivedArgs = null; + _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Shift); - VerifyAdded("Baz" ,"Qux"); + VerifyAdded("Baz", "Qux"); - receivedArgs = null; - _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift); + receivedArgs = null; + _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift); - VerifyRemoved("Qux"); + VerifyRemoved("Qux"); + } } [Fact] public void Duplicate_Items_Are_Added_To_SelectedItems_In_Order() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, - SelectionMode = SelectionMode.Multiple, - }; + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, + SelectionMode = SelectionMode.Multiple, + }; - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[0]); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[0]); - Assert.Equal(new[] { "Foo" }, target.SelectedItems); + Assert.Equal(new[] { "Foo" }, target.SelectedItems); - _helper.Click((Interactive)target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control); + _helper.Click((Interactive)target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control); - Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); + Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); - _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); + _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); - Assert.Equal(new[] { "Foo", "Bar", "Foo" }, target.SelectedItems); + Assert.Equal(new[] { "Foo", "Bar", "Foo" }, target.SelectedItems); - _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Control); + _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Control); - Assert.Equal(new[] { "Foo", "Bar", "Foo", "Bar" }, target.SelectedItems); + Assert.Equal(new[] { "Foo", "Bar", "Foo", "Bar" }, target.SelectedItems); + } } [Fact] @@ -1158,70 +1189,79 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Left_Click_On_SelectedItem_Should_Clear_Existing_Selection() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - target.SelectAll(); - - Assert.Equal(3, target.SelectedItems.Count); - - _helper.Click((Interactive)target.Presenter.Panel.Children[0]); - - Assert.Equal(1, target.SelectedItems.Count); - Assert.Equal(new[] { "Foo", }, target.SelectedItems); - Assert.Equal(new[] { 0 }, SelectedContainers(target)); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + target.SelectAll(); + + Assert.Equal(3, target.SelectedItems.Count); + + _helper.Click((Interactive)target.Presenter.Panel.Children[0]); + + Assert.Equal(1, target.SelectedItems.Count); + Assert.Equal(new[] { "Foo", }, target.SelectedItems); + Assert.Equal(new[] { 0 }, SelectedContainers(target)); + } } [Fact] public void Right_Click_On_SelectedItem_Should_Not_Clear_Existing_Selection() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - target.SelectAll(); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + target.SelectAll(); - Assert.Equal(3, target.SelectedItems.Count); + Assert.Equal(3, target.SelectedItems.Count); - _helper.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right); + _helper.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right); - Assert.Equal(3, target.SelectedItems.Count); + Assert.Equal(3, target.SelectedItems.Count); + } } [Fact] public void Right_Click_On_UnselectedItem_Should_Clear_Existing_Selection() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - _helper.Click((Interactive)target.Presenter.Panel.Children[0]); - _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Shift); - - Assert.Equal(2, target.SelectedItems.Count); - - _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right); - - Assert.Equal(1, target.SelectedItems.Count); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + _helper.Click((Interactive)target.Presenter.Panel.Children[0]); + _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Shift); + + Assert.Equal(2, target.SelectedItems.Count); + + _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right); + + Assert.Equal(1, target.SelectedItems.Count); + } } [Fact] @@ -1253,41 +1293,47 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Shift_Right_Click_Should_Not_Select_Multiple() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - - _helper.Click((Interactive)target.Presenter.Panel.Children[0]); - _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Shift); - - Assert.Equal(1, target.SelectedItems.Count); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + _helper.Click((Interactive)target.Presenter.Panel.Children[0]); + _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Shift); + + Assert.Equal(1, target.SelectedItems.Count); + } } [Fact] public void Ctrl_Right_Click_Should_Not_Select_Multiple() { - var target = new ListBox + using (UnitTestApplication.Start()) { - Template = Template(), - Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), - SelectionMode = SelectionMode.Multiple, - }; - - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - - _helper.Click((Interactive)target.Presenter.Panel.Children[0]); - _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Control); - - Assert.Equal(1, target.SelectedItems.Count); + var target = new ListBox + { + Template = Template(), + Items = new[] { "Foo", "Bar", "Baz" }, + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + _helper.Click((Interactive)target.Presenter.Panel.Children[0]); + _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Control); + + Assert.Equal(1, target.SelectedItems.Count); + } } [Fact] diff --git a/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs b/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs index eb4b88956d..c74f13b808 100644 --- a/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs +++ b/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs @@ -48,5 +48,49 @@ namespace Avalonia.Controls.UnitTests Assert.False(target.IsMeasureValid); } } + + [Fact] + public void Changing_Inlines_Should_Invalidate_Measure() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + var target = new RichTextBlock(); + + var inlines = new InlineCollection { new Run("Hello") }; + + target.Measure(Size.Infinity); + + Assert.True(target.IsMeasureValid); + + target.Inlines = inlines; + + Assert.False(target.IsMeasureValid); + } + } + + [Fact] + public void Changing_Inlines_Should_Reset_Inlines_Parent() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + var target = new RichTextBlock(); + + var run = new Run("Hello"); + + target.Inlines.Add(run); + + target.Measure(Size.Infinity); + + Assert.True(target.IsMeasureValid); + + target.Inlines = null; + + Assert.Null(run.Parent); + + target.Inlines = new InlineCollection { run }; + + Assert.Equal(target, run.Parent); + } + } } } diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index d784caf2db..9cf21423a3 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -18,6 +18,7 @@ using Avalonia.LogicalTree; using Avalonia.Styling; using Avalonia.UnitTests; using JetBrains.Annotations; +using Moq; using Xunit; namespace Avalonia.Controls.UnitTests @@ -885,28 +886,31 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Right_Click_On_SelectedItem_Should_Not_Clear_Existing_Selection() { - var tree = CreateTestTreeData(); - var target = new TreeView + using (UnitTestApplication.Start()) { - Template = CreateTreeViewTemplate(), - Items = tree, - SelectionMode = SelectionMode.Multiple, - }; - - var visualRoot = new TestRoot(); - visualRoot.Child = target; + var tree = CreateTestTreeData(); + var target = new TreeView + { + Template = CreateTreeViewTemplate(), + Items = tree, + SelectionMode = SelectionMode.Multiple, + }; + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + var visualRoot = new TestRoot(); + visualRoot.Child = target; - CreateNodeDataTemplate(target); - ApplyTemplates(target); - target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]); - target.SelectAll(); + CreateNodeDataTemplate(target); + ApplyTemplates(target); + target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]); + target.SelectAll(); - AssertChildrenSelected(target, tree[0]); - Assert.Equal(5, target.SelectedItems.Count); + AssertChildrenSelected(target, tree[0]); + Assert.Equal(5, target.SelectedItems.Count); - _mouse.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right); + _mouse.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right); - Assert.Equal(5, target.SelectedItems.Count); + Assert.Equal(5, target.SelectedItems.Count); + } } [Fact] diff --git a/tests/Avalonia.DesignerSupport.TestApp/App.xaml b/tests/Avalonia.DesignerSupport.TestApp/App.xaml index 5a33ffff80..ad32431b37 100644 --- a/tests/Avalonia.DesignerSupport.TestApp/App.xaml +++ b/tests/Avalonia.DesignerSupport.TestApp/App.xaml @@ -1,10 +1,7 @@ - - - - - - + + + + diff --git a/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj b/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj index f66b2b0457..278b0e087e 100644 --- a/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj +++ b/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj @@ -21,7 +21,7 @@ - + diff --git a/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj index 52acc78db1..4a90da77e7 100644 --- a/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj +++ b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj @@ -13,7 +13,7 @@ - + diff --git a/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs b/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs index d1d231466f..3f1fe7de12 100644 --- a/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs @@ -60,6 +60,8 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Select_Child_With_Alt_Arrow_Keys() { + MovePointerOutOfTheWay(); + new Actions(_session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys(Keys.Down + Keys.Enter) @@ -72,6 +74,8 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Select_Grandchild_With_Alt_Arrow_Keys() { + MovePointerOutOfTheWay(); + new Actions(_session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys(Keys.Down + Keys.Down + Keys.Right + Keys.Enter) @@ -84,6 +88,8 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Select_Child_With_Alt_Access_Keys() { + MovePointerOutOfTheWay(); + new Actions(_session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys("rc") @@ -96,6 +102,8 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Select_Grandchild_With_Alt_Access_Keys() { + MovePointerOutOfTheWay(); + new Actions(_session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys("rhg") @@ -111,6 +119,8 @@ namespace Avalonia.IntegrationTests.Appium var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); + MovePointerOutOfTheWay(); + new Actions(_session) .SendKeys(Keys.Down + Keys.Enter) .Perform(); @@ -125,6 +135,8 @@ namespace Avalonia.IntegrationTests.Appium var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); + MovePointerOutOfTheWay(); + new Actions(_session) .SendKeys(Keys.Down + Keys.Down + Keys.Right + Keys.Enter) .Perform(); @@ -159,5 +171,15 @@ namespace Avalonia.IntegrationTests.Appium Assert.True(textBox.GetIsFocused()); } + + private void MovePointerOutOfTheWay() + { + // Move the pointer to the menu tab item so that it's not over the menu in preparation + // for key press tests. This prevents the mouse accidentially selecting the wrong item + // by hovering. + var tabs = _session.FindElementByAccessibilityId("MainTabs"); + var tab = tabs.FindElementByName("Menu"); + tab.MovePointerOver(); + } } } diff --git a/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj b/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj index a00b24bdd7..4572f7ae7c 100644 --- a/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj +++ b/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs index d9ea3e374c..979dbec674 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using Avalonia.Controls; @@ -217,6 +218,37 @@ namespace Avalonia.Markup.UnitTests.Data } } + [Fact] + public void Should_Not_Pass_UnsetValue_To_MultiBinding_During_ApplyTemplate() + { + var converter = new MultiConverter(); + var source = new Button + { + Content = "foo", + Template = new FuncControlTemplate