Browse Source

Merge branch 'master' into manual-fbo

# Conflicts:
#	src/Avalonia.Visuals/ApiCompatBaseline.txt
win-ui-comp-with-manual-fbo
Dan Walmsley 5 years ago
parent
commit
3f5c22e65f
  1. 14
      nukebuild/Build.cs
  2. 17
      samples/ControlCatalog/Pages/DataGridPage.xaml
  3. 3
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  4. 2
      src/Avalonia.Animation/KeySplineTypeConverter.cs
  5. 4
      src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
  6. 5
      src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
  7. 24
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  8. 34
      src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
  9. 39
      src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
  10. 231
      src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
  11. 21
      src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
  12. 22
      src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs
  13. 9
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  14. 4
      src/Avalonia.Controls/ComboBox.cs
  15. 6
      src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
  16. 9
      src/Avalonia.Controls/IconElement.cs
  17. 21
      src/Avalonia.Controls/PathIcon.cs
  18. 4
      src/Avalonia.Controls/Primitives/AccessText.cs
  19. 21
      src/Avalonia.Controls/Primitives/Popup.cs
  20. 5
      src/Avalonia.Controls/TextBlock.cs
  21. 2
      src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  22. 8
      src/Avalonia.Native/Avalonia.Native.csproj
  23. 3
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  24. 3
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  25. 4
      src/Avalonia.Themes.Default/ComboBox.xaml
  26. 3
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  27. 2
      src/Avalonia.Themes.Default/MenuItem.xaml
  28. 18
      src/Avalonia.Themes.Default/PathIcon.xaml
  29. 2
      src/Avalonia.Themes.Fluent/Accents/Base.xaml
  30. 33
      src/Avalonia.Themes.Fluent/CheckBox.xaml
  31. 3
      src/Avalonia.Themes.Fluent/ComboBox.xaml
  32. 2
      src/Avalonia.Themes.Fluent/ContextMenu.xaml
  33. 3
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  34. 85
      src/Avalonia.Themes.Fluent/ListBoxItem.xaml
  35. 4
      src/Avalonia.Themes.Fluent/MenuItem.xaml
  36. 26
      src/Avalonia.Themes.Fluent/PathIcon.xaml
  37. 92
      src/Avalonia.Themes.Fluent/ScrollViewer.xaml
  38. 22
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  39. 5
      src/Avalonia.Visuals/Media/DrawingContext.cs
  40. 49
      src/Avalonia.Visuals/Media/GlyphRun.cs
  41. 13
      src/Avalonia.Visuals/Media/GlyphRunDrawing.cs
  42. 17
      src/Avalonia.Visuals/Media/TextDecoration.cs
  43. 7
      src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs
  44. 11
      src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
  45. 6
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
  46. 10
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  47. 3
      src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
  48. 29
      src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
  49. 2
      src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs
  50. 3
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  51. 19
      src/Avalonia.Visuals/Point.cs
  52. 4
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  53. 13
      src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs
  54. 19
      src/Avalonia.Visuals/Size.cs
  55. 23
      src/Avalonia.Visuals/Thickness.cs
  56. 19
      src/Avalonia.Visuals/Vector.cs
  57. 8
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  58. 7
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  59. 4
      tests/Avalonia.Base.UnitTests/Data/Core/Plugins/DataAnnotationsValidationPluginTests.cs
  60. 2
      tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
  61. 10
      tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs
  62. 45
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  63. 2
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs
  64. 50
      tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs

14
nukebuild/Build.cs

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

17
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -11,12 +11,17 @@
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,*">
<Grid RowDefinitions="Auto,Auto,*">
<StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
<TextBlock Classes="h1">DataGrid</TextBlock>
<TextBlock Classes="h2">A control for displaying and interacting with a data source.</TextBlock>
</StackPanel>
<TabControl Grid.Row="1">
<StackPanel Grid.Row="1" Spacing="4" Orientation="Horizontal" IsVisible="{Binding #EditableTab.IsSelected}">
<TextBlock Text="FontSize:" VerticalAlignment="Center"/>
<Slider x:Name="FontSizeSlider" Minimum="5" Maximum="30" Value="14" Width="100" VerticalAlignment="Center" />
<CheckBox x:Name="IsThreeStateCheckBox" IsChecked="False" Content="IsThreeState"/>
</StackPanel>
<TabControl Grid.Row="2">
<TabItem Header="DataGrid">
<DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All">
<DataGrid.Columns>
@ -39,13 +44,13 @@
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Header="Editable">
<TabItem x:Name="EditableTab" Header="Editable">
<Grid RowDefinitions="*,Auto">
<DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" />
<DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" />
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" IsThreeState="{Binding #IsThreeStateCheckBox.IsChecked, Mode=OneWay}" />
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Name="btnAdd" Margin="12,0,12,12" Content="Add" HorizontalAlignment="Right" />

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

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

2
src/Avalonia.Animation/KeySplineTypeConverter.cs

@ -19,7 +19,7 @@ namespace Avalonia.Animation
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return KeySpline.Parse((string)value, culture);
return KeySpline.Parse((string)value, CultureInfo.InvariantCulture);
}
}
}

4
src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs

@ -63,12 +63,12 @@ namespace Avalonia.Data.Core.Plugins
{
if (errors.Count == 1)
{
return new ValidationException(errors[0].ErrorMessage);
return new DataValidationException(errors[0].ErrorMessage);
}
else
{
return new AggregateException(
errors.Select(x => new ValidationException(x.ErrorMessage)));
errors.Select(x => new DataValidationException(x.ErrorMessage)));
}
}
}

5
src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt

@ -0,0 +1,5 @@
Compat issues with assembly Avalonia.Controls.DataGrid:
MembersMustExist : Member 'public Avalonia.StyledProperty<System.String> Avalonia.StyledProperty<System.String> Avalonia.Controls.DataGridTextColumn.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.String Avalonia.Controls.DataGridTextColumn.FontFamily.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.DataGridTextColumn.FontFamily.set(System.String)' does not exist in the implementation but it does exist in the contract.
Total Issues: 3

24
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -31,7 +31,7 @@ namespace Avalonia.Controls
/// <summary>
/// Displays data in a customizable grid.
/// </summary>
[PseudoClasses(":invalid")]
[PseudoClasses(":invalid", ":empty-rows", ":empty-columns")]
public partial class DataGrid : TemplatedControl
{
private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter";
@ -711,6 +711,7 @@ namespace Avalonia.Controls
DisplayData = new DataGridDisplayData(this);
ColumnsInternal = CreateColumnsInstance();
ColumnsInternal.CollectionChanged += ColumnsInternal_CollectionChanged;
RowHeightEstimate = DATAGRID_defaultRowHeight;
RowDetailsHeightEstimate = 0;
@ -727,6 +728,8 @@ namespace Avalonia.Controls
CurrentCellCoordinates = new DataGridCellCoordinates(-1, -1);
RowGroupHeaderHeightEstimate = DATAGRID_defaultRowHeight;
UpdatePseudoClasses();
}
private void SetValueNoCallback<T>(AvaloniaProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
@ -851,9 +854,27 @@ namespace Avalonia.Controls
// can be set when the DataGrid is not part of the visual tree
_measured = false;
InvalidateMeasure();
UpdatePseudoClasses();
}
}
private void ColumnsInternal_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add
|| e.Action == NotifyCollectionChangedAction.Remove
|| e.Action == NotifyCollectionChangedAction.Reset)
{
UpdatePseudoClasses();
}
}
internal void UpdatePseudoClasses()
{
PseudoClasses.Set(":empty-columns", !ColumnsInternal.GetVisibleColumns().Any());
PseudoClasses.Set(":empty-rows", !DataConnection.Any());
}
private void OnSelectedIndexChanged(AvaloniaPropertyChangedEventArgs e)
{
if (!_areHandlersSuspended)
@ -1348,7 +1369,6 @@ namespace Avalonia.Controls
internal DataGridColumnCollection ColumnsInternal
{
get;
private set;
}
internal int AnchorSlot

34
src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs

@ -17,9 +17,7 @@ namespace Avalonia.Controls
/// </summary>
public class DataGridCheckBoxColumn : DataGridBoundColumn
{
private bool _beganEditWithKeyboard;
private bool _isThreeState;
private CheckBox _currentCheckBox;
private DataGrid _owningGrid;
@ -31,6 +29,12 @@ namespace Avalonia.Controls
BindingTarget = CheckBox.IsCheckedProperty;
}
/// <summary>
/// Defines the <see cref="IsThreeState"/> property.
/// </summary>
public static StyledProperty<bool> IsThreeStateProperty =
CheckBox.IsThreeStateProperty.AddOwner<DataGridCheckBoxColumn>();
/// <summary>
/// Gets or sets a value that indicates whether the hosted <see cref="T:System.Windows.Controls.CheckBox" /> controls allow three states or two.
/// </summary>
@ -39,17 +43,17 @@ namespace Avalonia.Controls
/// </returns>
public bool IsThreeState
{
get
{
return _isThreeState;
}
set
get => GetValue(IsThreeStateProperty);
set => SetValue(IsThreeStateProperty, value);
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == IsThreeStateProperty)
{
if (_isThreeState != value)
{
_isThreeState = value;
NotifyPropertyChanged(nameof(IsThreeState));
}
NotifyPropertyChanged(change.Property.Name);
}
}
@ -203,9 +207,9 @@ namespace Avalonia.Controls
{
throw new ArgumentNullException("element");
}
if(element is CheckBox checkBox)
if (element is CheckBox checkBox)
{
checkBox.IsThreeState = IsThreeState;
DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
}
else
{
@ -229,7 +233,7 @@ namespace Avalonia.Controls
{
checkBox.HorizontalAlignment = HorizontalAlignment.Center;
checkBox.VerticalAlignment = VerticalAlignment.Center;
checkBox.IsThreeState = IsThreeState;
DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
}
private bool EnsureOwningGrid()

39
src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs

@ -77,24 +77,7 @@ namespace Avalonia.Controls
private set;
}
public int Count
{
get
{
IList list = List;
if (list != null)
{
return list.Count;
}
if(DataSource is DataGridCollectionView cv)
{
return cv.Count;
}
return DataSource?.Cast<object>().Count() ?? 0;
}
}
public int Count => GetCount(true);
public bool DataIsPrimitive
{
@ -210,6 +193,24 @@ namespace Avalonia.Controls
}
}
internal bool Any()
{
return GetCount(false) > 0;
}
/// <param name="allowSlow">When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.</param>
private int GetCount(bool allowSlow)
{
return DataSource switch
{
ICollection collection => collection.Count,
DataGridCollectionView cv => cv.Count,
IEnumerable enumerable when allowSlow => enumerable.Cast<object>().Count(),
IEnumerable enumerable when !allowSlow => enumerable.Cast<object>().Any() ? 1 : 0,
_ => 0
};
}
/// <summary>
/// Puts the entity into editing mode if possible
/// </summary>
@ -675,6 +676,8 @@ namespace Avalonia.Controls
}
break;
}
_owner.UpdatePseudoClasses();
}
private void UpdateDataProperties()

231
src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs

@ -20,11 +20,6 @@ namespace Avalonia.Controls
{
private const string DATAGRID_TextColumnCellTextBlockMarginKey = "DataGridTextColumnCellTextBlockMargin";
private double? _fontSize;
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
private IBrush _foreground;
/// <summary>
/// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridTextColumn" /> class.
/// </summary>
@ -36,18 +31,24 @@ namespace Avalonia.Controls
/// <summary>
/// Identifies the FontFamily dependency property.
/// </summary>
public static readonly StyledProperty<string> FontFamilyProperty =
AvaloniaProperty.Register<DataGridTextColumn, string>(nameof(FontFamily));
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
TextBlock.FontFamilyProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font name.
/// </summary>
public string FontFamily
public FontFamily FontFamily
{
get { return GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
get => GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
/// <summary>
/// Identifies the FontSize dependency property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font size.
/// </summary>
@ -55,74 +56,66 @@ namespace Avalonia.Controls
[DefaultValue(double.NaN)]
public double FontSize
{
get
{
return _fontSize ?? Double.NaN;
}
set
{
if (_fontSize != value)
{
_fontSize = value;
NotifyPropertyChanged(nameof(FontSize));
}
}
get => GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
/// <summary>
/// Identifies the FontStyle dependency property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
TextBlock.FontStyleProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font style.
/// </summary>
public FontStyle FontStyle
{
get
{
return _fontStyle ?? FontStyle.Normal;
}
set
{
if (_fontStyle != value)
{
_fontStyle = value;
NotifyPropertyChanged(nameof(FontStyle));
}
}
get => GetValue(FontStyleProperty);
set => SetValue(FontStyleProperty, value);
}
/// <summary>
/// Identifies the FontWeight dependency property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
TextBlock.FontWeightProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font weight or thickness.
/// </summary>
public FontWeight FontWeight
{
get
{
return _fontWeight ?? FontWeight.Normal;
}
set
{
if (_fontWeight != value)
{
_fontWeight = value;
NotifyPropertyChanged(nameof(FontWeight));
}
}
get => GetValue(FontWeightProperty);
set => SetValue(FontWeightProperty, value);
}
/// <summary>
/// Identifies the Foreground dependency property.
/// </summary>
public static readonly AttachedProperty<IBrush> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets a brush that describes the foreground of the column cells.
/// </summary>
public IBrush Foreground
{
get
{
return _foreground;
}
set
get => GetValue(ForegroundProperty);
set => SetValue(ForegroundProperty, value);
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == FontFamilyProperty
|| change.Property == FontSizeProperty
|| change.Property == FontStyleProperty
|| change.Property == FontWeightProperty
|| change.Property == ForegroundProperty)
{
if (_foreground != value)
{
_foreground = value;
NotifyPropertyChanged(nameof(Foreground));
}
NotifyPropertyChanged(change.Property.Name);
}
}
@ -154,26 +147,7 @@ namespace Avalonia.Controls
Background = new SolidColorBrush(Colors.Transparent)
};
if (IsSet(FontFamilyProperty))
{
textBox.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBox.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBox.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBox.FontWeight = _fontWeight.Value;
}
if (_foreground != null)
{
textBox.Foreground = _foreground;
}
SyncProperties(textBox);
return textBox;
}
@ -192,26 +166,8 @@ namespace Avalonia.Controls
VerticalAlignment = VerticalAlignment.Center
};
if (IsSet(FontFamilyProperty))
{
textBlockElement.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBlockElement.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBlockElement.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBlockElement.FontWeight = _fontWeight.Value;
}
if (_foreground != null)
{
textBlockElement.Foreground = _foreground;
}
SyncProperties(textBlockElement);
if (Binding != null)
{
textBlockElement.Bind(TextBlock.TextProperty, Binding);
@ -261,99 +217,42 @@ namespace Avalonia.Controls
throw new ArgumentNullException("element");
}
if(element is TextBox textBox)
if (element is AvaloniaObject content)
{
if (propertyName == nameof(FontFamily))
{
textBox.FontFamily = FontFamily;
DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
}
else if (propertyName == nameof(FontSize))
{
SetTextFontSize(textBox, TextBox.FontSizeProperty);
DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
}
else if (propertyName == nameof(FontStyle))
{
textBox.FontStyle = FontStyle;
DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
}
else if (propertyName == nameof(FontWeight))
{
textBox.FontWeight = FontWeight;
DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
}
else if (propertyName == nameof(Foreground))
{
textBox.Foreground = Foreground;
}
else
{
if (FontFamily != null)
{
textBox.FontFamily = FontFamily;
}
SetTextFontSize(textBox, TextBox.FontSizeProperty);
textBox.FontStyle = FontStyle;
textBox.FontWeight = FontWeight;
if (Foreground != null)
{
textBox.Foreground = Foreground;
}
}
}
else if (element is TextBlock textBlock)
{
if (propertyName == nameof(FontFamily))
{
textBlock.FontFamily = FontFamily;
}
else if (propertyName == nameof(FontSize))
{
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
}
else if (propertyName == nameof(FontStyle))
{
textBlock.FontStyle = FontStyle;
}
else if (propertyName == nameof(FontWeight))
{
textBlock.FontWeight = FontWeight;
}
else if (propertyName == nameof(Foreground))
{
textBlock.Foreground = Foreground;
}
else
{
if (FontFamily != null)
{
textBlock.FontFamily = FontFamily;
}
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
textBlock.FontStyle = FontStyle;
textBlock.FontWeight = FontWeight;
if (Foreground != null)
{
textBlock.Foreground = Foreground;
}
DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
}
else
{
throw DataGridError.DataGrid.ValueIsNotAnInstanceOfEitherOr("element", typeof(TextBox), typeof(TextBlock));
throw DataGridError.DataGrid.ValueIsNotAnInstanceOf("element", typeof(AvaloniaObject));
}
}
private void SetTextFontSize(AvaloniaObject textElement, AvaloniaProperty fontSizeProperty)
private void SyncProperties(AvaloniaObject content)
{
double newFontSize = FontSize;
if (double.IsNaN(newFontSize))
{
textElement.ClearValue(fontSizeProperty);
}
else
{
textElement.SetValue(fontSizeProperty, newFontSize);
}
DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
}
}

21
src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml

@ -588,18 +588,11 @@
<!--<DataGridColumnHeader Name="PART_TopRightCornerHeader"
Grid.Column="2"
Template="{StaticResource TopRightHeaderTemplate}" />-->
<!--<Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
<Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
Grid.ColumnSpan="3"
VerticalAlignment="Bottom"
StrokeThickness="1"
Height="1"
Fill="{DynamicResource DataGridGridLinesBrush}" />-->
<Border Name="PART_ColumnHeadersAndRowsSeparator"
Grid.ColumnSpan="3"
Height="2"
VerticalAlignment="Bottom"
BorderThickness="0,0,0,1"
BorderBrush="{DynamicResource DataGridGridLinesBrush}" />
Fill="{DynamicResource DataGridGridLinesBrush}" />
<DataGridRowsPresenter Name="PART_RowsPresenter"
Grid.Row="1"
@ -642,4 +635,14 @@
</ControlTemplate>
</Setter>
</Style>
<Style Selector="DataGrid:empty-columns /template/ DataGridColumnHeader#PART_TopLeftCornerHeader">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGrid:empty-columns /template/ DataGridColumnHeadersPresenter#PART_ColumnHeadersPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGrid:empty-columns /template/ Rectangle#PART_ColumnHeadersAndRowsSeparator">
<Setter Property="IsVisible" Value="False" />
</Style>
</Styles>

22
src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs

@ -0,0 +1,22 @@
namespace Avalonia.Controls
{
internal static class DataGridHelper
{
internal static void SyncColumnProperty<T>(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty<T> property)
{
SyncColumnProperty(column, content, property, property);
}
internal static void SyncColumnProperty<T>(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty<T> contentProperty, AvaloniaProperty<T> columnProperty)
{
if (!column.IsSet(columnProperty))
{
content.ClearValue(contentProperty);
}
else
{
content.SetValue(contentProperty, column.GetValue(columnProperty));
}
}
}
}

9
src/Avalonia.Controls/Calendar/CalendarDatePicker.cs

@ -420,7 +420,7 @@ namespace Avalonia.Controls
_calendar.DayButtonMouseUp -= Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged -= Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged -= Calendar_SelectedDatesChanged;
_calendar.PointerPressed -= Calendar_PointerPressed;
_calendar.PointerReleased -= Calendar_PointerReleased;
_calendar.KeyDown -= Calendar_KeyDown;
}
_calendar = e.NameScope.Find<Calendar>(ElementCalendar);
@ -435,7 +435,7 @@ namespace Avalonia.Controls
_calendar.DayButtonMouseUp += Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged += Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
_calendar.PointerPressed += Calendar_PointerPressed;
_calendar.PointerReleased += Calendar_PointerReleased;
_calendar.KeyDown += Calendar_KeyDown;
//_calendar.SizeChanged += new SizeChangedEventHandler(Calendar_SizeChanged);
//_calendar.IsTabStop = true;
@ -831,9 +831,10 @@ namespace Avalonia.Controls
}
}
}
private void Calendar_PointerPressed(object sender, PointerPressedEventArgs e)
private void Calendar_PointerReleased(object sender, PointerReleasedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
if (e.InitialPressMouseButton == MouseButton.Left)
{
e.Handled = true;
}

4
src/Avalonia.Controls/ComboBox.cs

@ -257,7 +257,7 @@ namespace Avalonia.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (!e.Handled)
{
@ -276,7 +276,7 @@ namespace Avalonia.Controls
}
}
base.OnPointerPressed(e);
base.OnPointerReleased(e);
}
/// <inheritdoc/>

6
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@ -47,11 +47,7 @@ namespace Avalonia.Controls.Generators
{
var container = item as T;
if (item == null)
{
return null;
}
else if (container != null)
if (container != null)
{
return container;
}

9
src/Avalonia.Controls/IconElement.cs

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

21
src/Avalonia.Controls/PathIcon.cs

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

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

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

21
src/Avalonia.Controls/Primitives/Popup.cs

@ -128,6 +128,7 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<bool> TopmostProperty =
AvaloniaProperty.Register<Popup, bool>(nameof(Topmost));
private bool _isOpenRequested = false;
private bool _isOpen;
private bool _ignoreIsOpenChanged;
private PopupOpenState? _openState;
@ -361,17 +362,19 @@ namespace Avalonia.Controls.Primitives
if (placementTarget == null)
{
throw new InvalidOperationException("Popup has no logical parent and PlacementTarget is null");
_isOpenRequested = true;
return;
}
var topLevel = placementTarget.VisualRoot as TopLevel;
if (topLevel == null)
{
throw new InvalidOperationException(
"Attempted to open a popup not attached to a TopLevel");
_isOpenRequested = true;
return;
}
_isOpenRequested = false;
var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver);
var handlerCleanup = new CompositeDisposable(5);
@ -492,6 +495,17 @@ namespace Avalonia.Controls.Primitives
return new Size();
}
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isOpenRequested)
{
Open();
}
}
/// <inheritdoc/>
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
@ -552,6 +566,7 @@ namespace Avalonia.Controls.Primitives
private void CloseCore()
{
_isOpenRequested = false;
if (_openState is null)
{
using (BeginIgnoringIsOpen())

5
src/Avalonia.Controls/TextBlock.cs

@ -434,7 +434,10 @@ namespace Avalonia.Controls
var padding = Padding;
TextLayout.Draw(context, new Point(padding.Left + offsetX, padding.Top));
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top)))
{
TextLayout.Draw(context);
}
}
/// <summary>

2
src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

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

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

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

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

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

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

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

4
src/Avalonia.Themes.Default/ComboBox.xaml

@ -26,6 +26,7 @@
<Setter Property="Padding" Value="4" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="PlaceholderForeground" Value="{DynamicResource ThemeForegroundBrush}" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
@ -69,7 +70,8 @@
IsLightDismissEnabled="True">
<Border BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="1">
<ScrollViewer>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

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

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

2
src/Avalonia.Themes.Default/MenuItem.xaml

@ -64,7 +64,7 @@
<Border Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

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

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

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

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

33
src/Avalonia.Themes.Fluent/CheckBox.xaml

@ -1,13 +1,10 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<CheckBox IsThreeState="True" IsChecked="True" />
<CheckBox IsThreeState="True" IsChecked="True" Content="Content" Foreground="Gold" />
</Border>
</Design.PreviewWith>
<Style Selector="CheckBox">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUnchecked}" />
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUnchecked}" />
<Setter Property="Padding" Value="8,0,0,0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
@ -21,10 +18,12 @@
<Setter Property="Template">
<ControlTemplate>
<Grid x:Name="RootGrid" ColumnDefinitions="20,*">
<Border x:Name="PART_Border" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource ControlCornerRadius}" />
<Border x:Name="PART_Border"
Grid.ColumnSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource ControlCornerRadius}" />
<Grid VerticalAlignment="Top" Height="32">
<Border x:Name="NormalRectangle"
@ -55,11 +54,11 @@
</Style>
<!-- Unchecked Normal State -->
<Style Selector="CheckBox /template/ ContentPresenter#ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" />
<Style Selector="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" />
</Style>
<Style Selector="CheckBox /template/ Border#PART_Border">
<Style Selector="CheckBox">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUnchecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUnchecked}" />
</Style>
@ -133,11 +132,11 @@
<!-- Checked Normal State -->
<Style Selector="CheckBox:checked /template/ ContentPresenter#ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" />
<Style Selector="CheckBox:checked">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" />
</Style>
<Style Selector="CheckBox:checked /template/ Border#PART_Border">
<Style Selector="CheckBox:checked">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundChecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushChecked}" />
</Style>
@ -213,11 +212,11 @@
<!-- Indeterminate Normal State -->
<Style Selector="CheckBox:indeterminate /template/ ContentPresenter#ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" />
<Style Selector="CheckBox:indeterminate">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" />
</Style>
<Style Selector="CheckBox:indeterminate /template/ Border#PART_Border">
<Style Selector="CheckBox:indeterminate">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminate}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminate}" />
</Style>

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

@ -133,7 +133,8 @@
Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
Margin="{DynamicResource ComboBoxDropdownContentMargin}"

2
src/Avalonia.Themes.Fluent/ContextMenu.xaml

@ -49,7 +49,7 @@
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

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

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

85
src/Avalonia.Themes.Fluent/ListBoxItem.xaml

@ -1,9 +1,13 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="0">
<ListBox>
<ListBoxItem IsEnabled="False">Disabled</ListBoxItem>
<ListBoxItem>Test</ListBoxItem>
<ListBoxItem Background="#66000000"
Padding="20">
Test
</ListBoxItem>
<ListBoxItem>Test</ListBoxItem>
</ListBox>
</Border>
@ -17,11 +21,7 @@
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="LayoutRoot" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Panel>
<Rectangle x:Name="PressedBackground" IsHitTestVisible="False" />
<ContentPresenter Name="PART_ContentPresenter"
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
@ -29,69 +29,66 @@
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Panel>
</Border>
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ListBoxItem /template/ ContentPresenter">
<Style Selector="ListBoxItem /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.FontWeight" Value="Normal" />
<Setter Property="TextBlock.FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
</Style>
<!-- Disabled State -->
<Style Selector="ListBoxItem:disabled /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlDisabledBaseMediumLowBrush}"/>
<!-- Disabled State -->
<Style Selector="ListBoxItem:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlDisabledBaseMediumLowBrush}" />
</Style>
<!-- PointerOver State -->
<Style Selector="ListBoxItem:pointerover /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListLowBrush}"/>
<!-- PointerOver State -->
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListLowBrush}" />
</Style>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Pressed State -->
<Style Selector="ListBoxItem:pressed /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListMediumBrush}"/>
<!-- Pressed State -->
<Style Selector="ListBoxItem:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListMediumBrush}" />
</Style>
<Style Selector="ListBoxItem:pressed /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected State -->
<Style Selector="ListBoxItem:selected /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}"/>
<!-- Selected State -->
<Style Selector="ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}" />
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected Unfocused State -->
<Style Selector="ListBoxItem:selected:not(:focus) /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}"/>
<!-- Selected Unfocused State -->
<Style Selector="ListBoxItem:selected:not(:focus) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}" />
</Style>
<Style Selector="ListBoxItem:selected:not(:focus) /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Style Selector="ListBoxItem:selected:not(:focus) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected PointerOver State -->
<Style Selector="ListBoxItem:selected:pointerover /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentMediumBrush}"/>
<!-- Selected PointerOver State -->
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentMediumBrush}" />
</Style>
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected Pressed State -->
<Style Selector="ListBoxItem:selected:pressed /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentHighBrush}"/>
<!-- Selected Pressed State -->
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentHighBrush}" />
</Style>
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
</Styles>

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

@ -123,7 +123,7 @@
MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
@ -171,7 +171,7 @@
MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

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

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

92
src/Avalonia.Themes.Fluent/ScrollViewer.xaml

@ -1,5 +1,21 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls">
<Design.PreviewWith>
<Grid ColumnDefinitions="*,20,*"
Height="300"
Width="200"
Margin="20">
<ScrollViewer>
<Border Height="1000" Background="#ccc"/>
</ScrollViewer>
<ScrollViewer Grid.Column="2" Classes="menuscroller">
<Border Height="1000" Background="#ccc"/>
</ScrollViewer>
</Grid>
</Design.PreviewWith>
<Style Selector="ScrollViewer">
<Setter Property="Background"
Value="Transparent" />
@ -66,4 +82,78 @@
<Setter Property="Opacity" Value="1" />
</Style>
<Style Selector="ScrollViewer.menuscroller">
<Setter Property="Template">
<ControlTemplate>
<DockPanel>
<RepeatButton DockPanel.Dock="Top"
BorderThickness="0"
Background="Transparent"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
RenderTransform="{x:Null}"
Command="{Binding LineUp, RelativeSource={RelativeSource TemplatedParent}}">
<RepeatButton.IsVisible>
<MultiBinding Converter="{x:Static converters:MenuScrollingVisibilityConverter.Instance}"
ConverterParameter="0">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="VerticalScrollBarVisibility"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Offset.Y"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Extent.Height"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Viewport.Height"/>
</MultiBinding>
</RepeatButton.IsVisible>
<Viewbox Width="{DynamicResource ScrollBarButtonArrowIconFontSize}"
Height="{DynamicResource ScrollBarButtonArrowIconFontSize}">
<Path VerticalAlignment="Center"
HorizontalAlignment="Center"
Data="M 19.091797 14.970703 L 10 5.888672 L 0.908203 14.970703 L 0.029297 14.091797 L 10 4.111328 L 19.970703 14.091797 Z"
Width="20"
Height="20" />
</Viewbox>
</RepeatButton>
<RepeatButton DockPanel.Dock="Bottom"
BorderThickness="0"
Background="Transparent"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
RenderTransform="{x:Null}"
Command="{Binding LineDown, RelativeSource={RelativeSource TemplatedParent}}">
<RepeatButton.IsVisible>
<MultiBinding Converter="{x:Static converters:MenuScrollingVisibilityConverter.Instance}"
ConverterParameter="100">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="VerticalScrollBarVisibility"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Offset.Y"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Extent.Height"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Viewport.Height"/>
</MultiBinding>
</RepeatButton.IsVisible>
<Viewbox Width="{DynamicResource ScrollBarButtonArrowIconFontSize}"
Height="{DynamicResource ScrollBarButtonArrowIconFontSize}">
<Path VerticalAlignment="Center"
HorizontalAlignment="Center"
Data="M 18.935547 4.560547 L 19.814453 5.439453 L 10 15.253906 L 0.185547 5.439453 L 1.064453 4.560547 L 10 13.496094 Z"
Width="20"
Height="20" />
</Viewbox>
</RepeatButton>
<ScrollContentPresenter Name="PART_ContentPresenter"
CanHorizontallyScroll="{TemplateBinding CanHorizontallyScroll}"
CanVerticallyScroll="{TemplateBinding CanVerticallyScroll}"
Content="{TemplateBinding Content}"
Extent="{TemplateBinding Extent, Mode=TwoWay}"
Margin="{TemplateBinding Padding}"
Offset="{TemplateBinding Offset, Mode=TwoWay}"
Viewport="{TemplateBinding Viewport, Mode=TwoWay}"/>
</DockPanel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollViewer.menuscroller /template/ RepeatButton > Viewbox > Path">
<Setter Property="Fill" Value="{DynamicResource ScrollBarButtonArrowForeground}" />
</Style>
<Style Selector="ScrollViewer.menuscroller /template/ RepeatButton:pointerover > Viewbox > Path">
<Setter Property="Fill" Value="{DynamicResource ScrollBarButtonArrowForegroundPointerOver}" />
</Style>
</Styles>

22
src/Avalonia.Visuals/ApiCompatBaseline.txt

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

5
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -206,14 +206,13 @@ namespace Avalonia.Media
/// </summary>
/// <param name="foreground">The foreground brush.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin">The baseline origin of the glyph run.</param>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
Contract.Requires<ArgumentNullException>(glyphRun != null);
if (foreground != null)
{
PlatformImpl.DrawGlyphRun(foreground, glyphRun, baselineOrigin);
PlatformImpl.DrawGlyphRun(foreground, glyphRun);
}
}

49
src/Avalonia.Visuals/Media/GlyphRun.cs

@ -16,8 +16,9 @@ namespace Avalonia.Media
private IGlyphRunImpl _glyphRunImpl;
private GlyphTypeface _glyphTypeface;
private double _fontRenderingEmSize;
private Rect? _bounds;
private Size? _size;
private int _biDiLevel;
private Point? _baselineOrigin;
private ReadOnlySlice<ushort> _glyphIndices;
private ReadOnlySlice<double> _glyphAdvances;
@ -89,6 +90,20 @@ namespace Avalonia.Media
set => Set(ref _fontRenderingEmSize, value);
}
/// <summary>
/// Gets or sets the baseline origin of the<see cref="GlyphRun"/>.
/// </summary>
public Point BaselineOrigin
{
get
{
_baselineOrigin ??= CalculateBaselineOrigin();
return _baselineOrigin.Value;
}
set => Set(ref _baselineOrigin, value);
}
/// <summary>
/// Gets or sets an array of <see cref="ushort"/> values that represent the glyph indices in the rendering physical font.
/// </summary>
@ -156,16 +171,13 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets the conservative bounding box of the <see cref="GlyphRun"/>.
/// </summary>
public Rect Bounds
public Size Size
{
get
{
if (_bounds == null)
{
_bounds = CalculateBounds();
}
_size ??= CalculateSize();
return _bounds.Value;
return _size.Value;
}
}
@ -200,7 +212,7 @@ namespace Avalonia.Media
if (characterHit.FirstCharacterIndex + characterHit.TrailingLength > Characters.End)
{
return Bounds.Width;
return Size.Width;
}
var glyphIndex = FindGlyphIndex(characterHit.FirstCharacterIndex);
@ -257,7 +269,7 @@ namespace Avalonia.Media
}
//After
if (distance > Bounds.Size.Width)
if (distance > Size.Width)
{
isInside = false;
@ -529,12 +541,21 @@ namespace Avalonia.Media
}
/// <summary>
/// Calculates the bounds of the <see cref="GlyphRun"/>.
/// Calculates the default baseline origin of the <see cref="GlyphRun"/>.
/// </summary>
/// <returns>The baseline origin.</returns>
private Point CalculateBaselineOrigin()
{
return new Point(0, -GlyphTypeface.Ascent * Scale);
}
/// <summary>
/// Calculates the size of the <see cref="GlyphRun"/>.
/// </summary>
/// <returns>
/// The calculated bounds.
/// </returns>
private Rect CalculateBounds()
private Size CalculateSize()
{
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
@ -555,7 +576,7 @@ namespace Avalonia.Media
}
}
return new Rect(0, GlyphTypeface.Ascent * Scale, width, height);
return new Size(width, height);
}
private void Set<T>(ref T field, T value)
@ -590,11 +611,15 @@ namespace Avalonia.Media
throw new InvalidOperationException();
}
_baselineOrigin = new Point(0, -GlyphTypeface.Ascent * Scale);
var platformRenderInterface = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
_glyphRunImpl = platformRenderInterface.CreateGlyphRun(this, out var width);
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
_size = new Size(width, height);
}
void IDisposable.Dispose()

13
src/Avalonia.Visuals/Media/GlyphRunDrawing.cs

@ -8,9 +8,6 @@
public static readonly StyledProperty<GlyphRun> GlyphRunProperty =
AvaloniaProperty.Register<GlyphRunDrawing, GlyphRun>(nameof(GlyphRun));
public static readonly StyledProperty<Point> BaselineOriginProperty =
AvaloniaProperty.Register<GlyphRunDrawing, Point>(nameof(BaselineOrigin));
public IBrush Foreground
{
get => GetValue(ForegroundProperty);
@ -23,12 +20,6 @@
set => SetValue(GlyphRunProperty, value);
}
public Point BaselineOrigin
{
get => GetValue(BaselineOriginProperty);
set => SetValue(BaselineOriginProperty, value);
}
public override void Draw(DrawingContext context)
{
if (GlyphRun == null)
@ -36,12 +27,12 @@
return;
}
context.DrawGlyphRun(Foreground, GlyphRun, BaselineOrigin);
context.DrawGlyphRun(Foreground, GlyphRun);
}
public override Rect GetBounds()
{
return GlyphRun?.Bounds ?? default;
return GlyphRun != null ? new Rect(GlyphRun.Size) : Rect.Empty;
}
}
}

17
src/Avalonia.Visuals/Media/TextDecoration.cs

@ -155,8 +155,7 @@ namespace Avalonia.Media
/// </summary>
/// <param name="drawingContext">The drawing context.</param>
/// <param name="shapedTextCharacters">The shaped characters that are decorated.</param>
/// <param name="origin">The origin.</param>
internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters, Point origin)
internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters)
{
var fontRenderingEmSize = shapedTextCharacters.Properties.FontRenderingEmSize;
var fontMetrics = shapedTextCharacters.FontMetrics;
@ -181,16 +180,20 @@ namespace Avalonia.Media
break;
}
var origin = new Point();
switch (Location)
{
case TextDecorationLocation.Overline:
origin += new Point(0, fontMetrics.Ascent);
case TextDecorationLocation.Baseline:
origin += shapedTextCharacters.GlyphRun.BaselineOrigin;
break;
case TextDecorationLocation.Strikethrough:
origin += new Point(0, -fontMetrics.StrikethroughPosition);
origin += new Point(shapedTextCharacters.GlyphRun.BaselineOrigin.X,
shapedTextCharacters.GlyphRun.BaselineOrigin.Y - fontMetrics.StrikethroughPosition);
break;
case TextDecorationLocation.Underline:
origin += new Point(0, -fontMetrics.UnderlinePosition);
origin += new Point(shapedTextCharacters.GlyphRun.BaselineOrigin.X,
shapedTextCharacters.GlyphRun.BaselineOrigin.Y - fontMetrics.UnderlinePosition);
break;
}
@ -207,7 +210,7 @@ namespace Avalonia.Media
var pen = new Pen(Stroke ?? shapedTextCharacters.Properties.ForegroundBrush, thickness,
new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap);
drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Bounds.Width, 0));
drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Size.Width, 0));
}
}
}

7
src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs

@ -6,15 +6,14 @@
public abstract class DrawableTextRun : TextRun
{
/// <summary>
/// Gets the bounds.
/// Gets the size.
/// </summary>
public abstract Rect Bounds { get; }
public abstract Size Size { get; }
/// <summary>
/// Draws the <see cref="DrawableTextRun"/> at the given origin.
/// </summary>
/// <param name="drawingContext">The drawing context.</param>
/// <param name="origin">The origin.</param>
public abstract void Draw(DrawingContext drawingContext, Point origin);
public abstract void Draw(DrawingContext drawingContext);
}
}

11
src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs

@ -26,7 +26,7 @@ namespace Avalonia.Media.TextFormatting
public override int TextSourceLength { get; }
/// <inheritdoc/>
public override Rect Bounds => GlyphRun.Bounds;
public override Size Size => GlyphRun.Size;
/// <summary>
/// Gets the font metrics.
@ -45,7 +45,7 @@ namespace Avalonia.Media.TextFormatting
public GlyphRun GlyphRun { get; }
/// <inheritdoc/>
public override void Draw(DrawingContext drawingContext, Point origin)
public override void Draw(DrawingContext drawingContext)
{
if (GlyphRun.GlyphIndices.Length == 0)
{
@ -64,11 +64,10 @@ namespace Avalonia.Media.TextFormatting
if (Properties.BackgroundBrush != null)
{
drawingContext.DrawRectangle(Properties.BackgroundBrush, null,
new Rect(origin.X, origin.Y + FontMetrics.Ascent, Bounds.Width, Bounds.Height));
drawingContext.DrawRectangle(Properties.BackgroundBrush, null, new Rect(Size));
}
drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun, origin);
drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun);
if (Properties.TextDecorations == null)
{
@ -77,7 +76,7 @@ namespace Avalonia.Media.TextFormatting
foreach (var textDecoration in Properties.TextDecorations)
{
textDecoration.Draw(drawingContext, this, origin);
textDecoration.Draw(drawingContext, this);
}
}

6
src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs

@ -52,7 +52,7 @@ namespace Avalonia.Media.TextFormatting
{
var glyphRun = textCharacters.GlyphRun;
if (glyphRun.Bounds.Width < availableWidth)
if (glyphRun.Size.Width < availableWidth)
{
return glyphRun.Characters.Length;
}
@ -348,7 +348,7 @@ namespace Avalonia.Media.TextFormatting
{
var currentRun = textRuns[runIndex];
if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
if (currentWidth + currentRun.Size.Width > availableWidth)
{
var measuredLength = MeasureCharacters(currentRun, paragraphWidth - currentWidth);
@ -421,7 +421,7 @@ namespace Avalonia.Media.TextFormatting
return new TextLineImpl(splitResult.First, textLineMetrics, lineBreak);
}
currentWidth += currentRun.GlyphRun.Bounds.Width;
currentWidth += currentRun.Size.Width;
currentLength += currentRun.GlyphRun.Characters.Length;

10
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@ -115,22 +115,24 @@ namespace Avalonia.Media.TextFormatting
/// Draws the text layout.
/// </summary>
/// <param name="context">The drawing context.</param>
/// <param name="origin">The origin.</param>
public void Draw(DrawingContext context, Point origin)
public void Draw(DrawingContext context)
{
if (!TextLines.Any())
{
return;
}
var currentY = origin.Y;
var currentY = 0.0;
foreach (var textLine in TextLines)
{
var offsetX = TextLine.GetParagraphOffsetX(textLine.LineMetrics.Size.Width, Size.Width,
_paragraphProperties.TextAlignment);
textLine.Draw(context, new Point(origin.X + offsetX, currentY));
using (context.PushPostTransform(Matrix.CreateTranslation(offsetX, currentY)))
{
textLine.Draw(context);
}
currentY += textLine.LineMetrics.Size.Height;
}

3
src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs

@ -51,8 +51,7 @@ namespace Avalonia.Media.TextFormatting
/// Draws the <see cref="TextLine"/> at the given origin.
/// </summary>
/// <param name="drawingContext">The drawing context.</param>
/// <param name="origin">The origin.</param>
public abstract void Draw(DrawingContext drawingContext, Point origin);
public abstract void Draw(DrawingContext drawingContext);
/// <summary>
/// Create a collapsed line based on collapsed text properties.

29
src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs

@ -33,17 +33,18 @@ namespace Avalonia.Media.TextFormatting
public override bool HasCollapsed { get; }
/// <inheritdoc/>
public override void Draw(DrawingContext drawingContext, Point origin)
public override void Draw(DrawingContext drawingContext)
{
var currentX = origin.X;
var currentX = 0.0;
foreach (var textRun in _textRuns)
{
var baselineOrigin = new Point(currentX, origin.Y + LineMetrics.TextBaseline);
textRun.Draw(drawingContext, baselineOrigin);
using (drawingContext.PushPostTransform(Matrix.CreateTranslation(currentX, 0)))
{
textRun.Draw(drawingContext);
}
currentX += textRun.Bounds.Width;
currentX += textRun.Size.Width;
}
}
@ -64,13 +65,13 @@ namespace Avalonia.Media.TextFormatting
var shapedSymbol = CreateShapedSymbol(collapsingProperties.Symbol);
var availableWidth = collapsingProperties.Width - shapedSymbol.Bounds.Width;
var availableWidth = collapsingProperties.Width - shapedSymbol.Size.Width;
while (runIndex < _textRuns.Count)
{
var currentRun = _textRuns[runIndex];
currentWidth += currentRun.GlyphRun.Bounds.Width;
currentWidth += currentRun.Size.Width;
if (currentWidth > availableWidth)
{
@ -125,7 +126,7 @@ namespace Avalonia.Media.TextFormatting
return new TextLineImpl(shapedTextCharacters, textLineMetrics, TextLineBreak, true);
}
availableWidth -= currentRun.GlyphRun.Bounds.Width;
availableWidth -= currentRun.Size.Width;
collapsedLength += currentRun.GlyphRun.Characters.Length;
@ -133,7 +134,7 @@ namespace Avalonia.Media.TextFormatting
}
textLineMetrics =
new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Bounds.Width),
new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Size.Width),
LineMetrics.TextBaseline, TextRange, LineMetrics.HasOverflowed);
return new TextLineImpl(new List<ShapedTextCharacters>(_textRuns) { shapedSymbol }, textLineMetrics, null,
@ -156,12 +157,12 @@ namespace Avalonia.Media.TextFormatting
{
characterHit = run.GlyphRun.GetCharacterHitFromDistance(distance, out _);
if (distance <= run.Bounds.Width)
if (distance <= run.Size.Width)
{
break;
}
distance -= run.Bounds.Width;
distance -= run.Size.Width;
}
return characterHit;
@ -229,7 +230,7 @@ namespace Avalonia.Media.TextFormatting
{
if (codepointIndex > textRun.Text.End)
{
currentDistance += textRun.Bounds.Width;
currentDistance += textRun.Size.Width;
continue;
}
@ -405,7 +406,7 @@ namespace Avalonia.Media.TextFormatting
for (var i = 0; i < shapedTextCharacters.Count; i++)
{
shapedWidth += shapedTextCharacters[i].Bounds.Width;
shapedWidth += shapedTextCharacters[i].Size.Width;
}
return shapedWidth;

2
src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs

@ -67,7 +67,7 @@ namespace Avalonia.Media.TextFormatting
var fontMetrics =
new FontMetrics(shapedRun.Properties.Typeface, shapedRun.Properties.FontRenderingEmSize);
lineWidth += shapedRun.Bounds.Width;
lineWidth += shapedRun.Size.Width;
if (ascent > fontMetrics.Ascent)
{

3
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@ -84,8 +84,7 @@ namespace Avalonia.Platform
/// </summary>
/// <param name="foreground">The foreground.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin">The baseline origin of the glyph run.</param>
void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin);
void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun);
/// <summary>
/// Creates a new <see cref="IRenderTargetBitmapImpl"/> that can be used as a render layer

19
src/Avalonia.Visuals/Point.cs

@ -267,5 +267,24 @@ namespace Avalonia
{
return new Point(_x, y);
}
/// <summary>
/// Deconstructs the point into its X and Y coordinates.
/// </summary>
/// <param name="x">The X coordinate.</param>
/// <param name="y">The Y coordinate.</param>
public void Deconstruct(out double x, out double y)
{
x = this._x;
y = this._y;
}
/// <summary>
/// Gets a value indicating whether the X and Y coordinates are zero.
/// </summary>
public bool IsDefault
{
get { return (_x == 0) && (_y == 0); }
}
}
}

4
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@ -204,13 +204,13 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
var next = NextDrawAs<GlyphRunNode>();
if (next == null || !next.Item.Equals(Transform, foreground, glyphRun))
{
Add(new GlyphRunNode(Transform, foreground, glyphRun, baselineOrigin, CreateChildScene(foreground)));
Add(new GlyphRunNode(Transform, foreground, glyphRun, CreateChildScene(foreground)));
}
else

13
src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.VisualTree;
@ -17,20 +18,17 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="transform">The transform.</param>
/// <param name="foreground">The foreground brush.</param>
/// <param name="glyphRun">The glyph run to draw.</param>
/// <param name="baselineOrigin">The baseline origin of the glyph run.</param>
/// <param name="childScenes">Child scenes for drawing visual brushes.</param>
public GlyphRunNode(
Matrix transform,
IBrush foreground,
GlyphRun glyphRun,
Point baselineOrigin,
IDictionary<IVisual, Scene> childScenes = null)
: base(glyphRun.Bounds.Translate(baselineOrigin), transform)
: base(new Rect(glyphRun.Size), transform)
{
Transform = transform;
Foreground = foreground?.ToImmutable();
GlyphRun = glyphRun;
BaselineOrigin = baselineOrigin;
ChildScenes = childScenes;
}
@ -49,11 +47,6 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
public GlyphRun GlyphRun { get; }
/// <summary>
/// Gets the baseline origin.
/// </summary>
public Point BaselineOrigin { get; set; }
/// <inheritdoc/>
public override IDictionary<IVisual, Scene> ChildScenes { get; }
@ -61,7 +54,7 @@ namespace Avalonia.Rendering.SceneGraph
public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawGlyphRun(Foreground, GlyphRun, BaselineOrigin);
context.DrawGlyphRun(Foreground, GlyphRun);
}
/// <summary>

19
src/Avalonia.Visuals/Size.cs

@ -276,5 +276,24 @@ namespace Avalonia
{
return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _width, _height);
}
/// <summary>
/// Deconstructs the size into its Width and Height values.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public void Deconstruct(out double width, out double height)
{
width = this._width;
height = this._height;
}
/// <summary>
/// Gets a value indicating whether the Width and Height values are zero.
/// </summary>
public bool IsDefault
{
get { return (_width == 0) && (_height == 0); }
}
}
}

23
src/Avalonia.Visuals/Thickness.cs

@ -272,5 +272,28 @@ namespace Avalonia
{
return $"{_left},{_top},{_right},{_bottom}";
}
/// <summary>
/// Deconstructor the thickness into its left, top, right and bottom thickness values.
/// </summary>
/// <param name="left">The thickness on the left.</param>
/// <param name="top">The thickness on the top.</param>
/// <param name="right">The thickness on the right.</param>
/// <param name="bottom">The thickness on the bottom.</param>
public void Deconstruct(out double left, out double top, out double right, out double bottom)
{
left = this._left;
top = this._top;
right = this._right;
bottom = this._bottom;
}
/// <summary>
/// Gets a value indicating whether the left, top, right and bottom thickness values are zero.
/// </summary>
public bool IsDefault
{
get { return (_left == 0) && (_top == 0) && (_right == 0) && (_bottom == 0); }
}
}
}

19
src/Avalonia.Visuals/Vector.cs

@ -333,5 +333,24 @@ namespace Avalonia
/// </summary>
public static Vector UnitY
=> new Vector(0, 1);
/// <summary>
/// Deconstructs the vector into its X and Y components.
/// </summary>
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
public void Deconstruct(out double x, out double y)
{
x = this._x;
y = this._y;
}
/// <summary>
/// Gets a value indicating whether the X and Y components are zero.
/// </summary>
public bool IsDefault
{
get { return (_x == 0) && (_y == 0); }
}
}
}

8
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -408,16 +408,16 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Bounds.Size))
using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl;
ConfigureTextRendering(paintWrapper);
Canvas.DrawText(glyphRunImpl.TextBlob, (float)baselineOrigin.X,
(float)baselineOrigin.Y, paintWrapper.Paint);
Canvas.DrawText(glyphRunImpl.TextBlob, (float)glyphRun.BaselineOrigin.X,
(float)glyphRun.BaselineOrigin.Y, paintWrapper.Paint);
}
}

7
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -324,13 +324,14 @@ namespace Avalonia.Direct2D1.Media
/// <param name="foreground">The foreground.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin"></param>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
using (var brush = CreateBrush(foreground, glyphRun.Bounds.Size))
using (var brush = CreateBrush(foreground, glyphRun.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl;
_renderTarget.DrawGlyphRun(baselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun, brush.PlatformBrush, MeasuringMode.Natural);
_renderTarget.DrawGlyphRun(glyphRun.BaselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun,
brush.PlatformBrush, MeasuringMode.Natural);
}
}

4
tests/Avalonia.Base.UnitTests/Data/Core/Plugins/DataAnnotationsValidationPluginTests.cs

@ -59,12 +59,12 @@ namespace Avalonia.Markup.UnitTests.Data.Plugins
{
new BindingNotification(5),
new BindingNotification(
new ValidationException(errmsg),
new DataValidationException(errmsg),
BindingErrorType.DataValidationError,
3),
new BindingNotification(7),
new BindingNotification(
new ValidationException(errmsg),
new DataValidationException(errmsg),
BindingErrorType.DataValidationError,
11),
}, result);

2
tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs

@ -2,7 +2,6 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.UnitTests;
@ -27,6 +26,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(target.IsDropDownOpen);
_helper.Down(target);
_helper.Up(target);
Assert.False(target.IsDropDownOpen);
}

10
tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs

@ -144,6 +144,16 @@ namespace Avalonia.Controls.UnitTests.Generators
Assert.Equal("bar", container.Content);
}
[Fact]
public void Materialize_Should_Create_Containers_When_Item_Is_Null()
{
var owner = new Decorator();
var target = new ItemContainerGenerator<ListBoxItem>(owner, ListBoxItem.ContentProperty, null);
var container = (ListBoxItem)target.Materialize(0, null).ContainerControl;
Assert.True(container != null, "The containers is not materialized.");
}
private IList<ItemContainerInfo> Materialize(
IItemContainerGenerator generator,
int index,

45
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -21,7 +21,50 @@ namespace Avalonia.Controls.UnitTests.Primitives
public class PopupTests
{
protected bool UsePopupHost;
[Fact]
public void Popup_Open_Without_Target_Should_Attach_Itself_Later()
{
using (CreateServices())
{
int openedEvent = 0;
var target = new Popup();
target.Opened += (s, a) => openedEvent++;
target.IsOpen = true;
var window = PreparedWindow(target);
window.Show();
Assert.Equal(1, openedEvent);
}
}
[Fact]
public void Popup_Without_TopLevel_Shouldnt_Call_Open()
{
int openedEvent = 0;
var target = new Popup();
target.Opened += (s, a) => openedEvent++;
target.IsOpen = true;
Assert.Equal(0, openedEvent);
}
[Fact]
public void Opening_Popup_Shouldnt_Throw_When_Not_In_Visual_Tree()
{
var target = new Popup();
target.IsOpen = true;
}
[Fact]
public void Opening_Popup_Shouldnt_Throw_When_In_Tree_Without_TopLevel()
{
Control c = new Control();
var target = new Popup();
((ISetLogicalParent)target).SetParent(c);
target.IsOpen = true;
}
[Fact]
public void Setting_Child_Should_Set_Child_Controls_LogicalParent()
{

2
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs

@ -369,7 +369,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var glyphRun = shapedRun.GlyphRun;
var width = glyphRun.Bounds.Width;
var width = glyphRun.Size.Width;
var characterHit = glyphRun.GetCharacterHitFromDistance(width, out _);

50
tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs

@ -119,6 +119,56 @@ namespace Avalonia.Visuals.UnitTests.Media
}
}
[InlineData(new double[] { 10, 10, 10 }, new ushort[] { 0, 0, 0 }, 0)]
[InlineData(new double[] { 10, 10, 10 }, new ushort[] { 0, 0, 0 }, 1)]
[InlineData(new double[] { 10, 10, 10, 10 }, new ushort[] { 0, 0, 0, 3 }, 0)]
[InlineData(new double[] { 10, 10, 10, 10 }, new ushort[] { 3, 0, 0, 0 }, 1)]
[InlineData(new double[] { 10, 10, 10, 10, 10 }, new ushort[] { 0, 1, 1, 1, 4 }, 0)]
[InlineData(new double[] { 10, 10, 10, 10, 10 }, new ushort[] { 4, 1, 1, 1, 0 }, 1)]
[Theory]
public void Should_Find_Glyph_Index(double[] advances, ushort[] clusters, int bidiLevel)
{
using (var glyphRun = CreateGlyphRun(advances, clusters, bidiLevel))
{
if (glyphRun.IsLeftToRight)
{
for (var i = 0; i < clusters.Length; i++)
{
var cluster = clusters[i];
var found = glyphRun.FindGlyphIndex(cluster);
var expected = i;
while (expected - 1 >= 0 && clusters[expected - 1] == cluster)
{
expected--;
}
Assert.Equal(expected, found);
}
}
else
{
for (var i = clusters.Length - 1; i > 0; i--)
{
var cluster = clusters[i];
var found = glyphRun.FindGlyphIndex(cluster);
var expected = i;
while (expected + 1 < clusters.Length && clusters[expected + 1] == cluster)
{
expected++;
}
Assert.Equal(expected, found);
}
}
}
}
private static GlyphRun CreateGlyphRun(double[] glyphAdvances, ushort[] glyphClusters, int bidiLevel = 0)
{
var count = glyphAdvances.Length;

Loading…
Cancel
Save