diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index cb50cba540..22f4e9be1f 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -81,7 +81,7 @@ namespace ControlCatalog
public override void Initialize()
{
- Styles.Insert(0, FluentDark);
+ Styles.Insert(0, FluentLight);
AvaloniaXamlLoader.Load(this);
}
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 790813fda0..bd5beafe29 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -77,8 +77,8 @@
Full Decorations
- Fluent - Dark
Fluent - Light
+ Fluent - Dark
Simple - Light
Simple - Dark
diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs
index b0c205246e..c84f2f06b6 100644
--- a/samples/ControlCatalog/MainView.xaml.cs
+++ b/samples/ControlCatalog/MainView.xaml.cs
@@ -38,10 +38,10 @@ namespace ControlCatalog
switch (themes.SelectedIndex)
{
case 0:
- Application.Current.Styles[0] = App.FluentDark;
+ Application.Current.Styles[0] = App.FluentLight;
break;
case 1:
- Application.Current.Styles[0] = App.FluentLight;
+ Application.Current.Styles[0] = App.FluentDark;
break;
case 2:
Application.Current.Styles[0] = App.DefaultLight;
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 65233f9230..6645d25b5d 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -113,16 +113,8 @@ namespace Avalonia
/// The binding information.
public IBinding this[IndexerDescriptor binding]
{
- get
- {
- return new IndexerBinding(this, binding.Property, binding.Mode);
- }
-
- set
- {
- var sourceBinding = value as IBinding;
- this.Bind(binding.Property, sourceBinding);
- }
+ get { return new IndexerBinding(this, binding.Property, binding.Mode); }
+ set { this.Bind(binding.Property, value); }
}
public bool CheckAccess() => Dispatcher.UIThread.CheckAccess();
diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs
index e9ea942142..e830717b95 100644
--- a/src/Avalonia.Controls/Calendar/CalendarItem.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs
@@ -36,11 +36,7 @@ namespace Avalonia.Controls.Primitives
private Button _headerButton;
private Button _nextButton;
private Button _previousButton;
- private Grid _monthView;
- private Grid _yearView;
private ITemplate _dayTitleTemplate;
- private CalendarButton _lastCalendarButton;
- private CalendarDayButton _lastCalendarDayButton;
private DateTime _currentMonth;
private bool _isMouseLeftButtonDown = false;
@@ -160,38 +156,12 @@ namespace Avalonia.Controls.Primitives
///
/// Gets the Grid that hosts the content when in month mode.
///
- internal Grid MonthView
- {
- get { return _monthView; }
- private set
- {
- if (_monthView != null)
- _monthView.PointerLeave -= MonthView_MouseLeave;
-
- _monthView = value;
-
- if (_monthView != null)
- _monthView.PointerLeave += MonthView_MouseLeave;
- }
- }
+ internal Grid MonthView { get; set; }
///
/// Gets the Grid that hosts the content when in year or decade mode.
///
- internal Grid YearView
- {
- get { return _yearView; }
- private set
- {
- if (_yearView != null)
- _yearView.PointerLeave -= YearView_MouseLeave;
-
- _yearView = value;
-
- if (_yearView != null)
- _yearView.PointerLeave += YearView_MouseLeave;
- }
- }
-
+ internal Grid YearView { get; set; }
+
private void PopulateGrids()
{
if (MonthView != null)
@@ -226,7 +196,6 @@ namespace Avalonia.Controls.Primitives
cell.CalendarDayButtonMouseDown += Cell_MouseLeftButtonDown;
cell.CalendarDayButtonMouseUp += Cell_MouseLeftButtonUp;
cell.PointerEnter += Cell_MouseEnter;
- cell.PointerLeave += Cell_MouseLeave;
cell.Click += Cell_Click;
children.Add(cell);
}
@@ -256,7 +225,6 @@ namespace Avalonia.Controls.Primitives
month.CalendarLeftMouseButtonDown += Month_CalendarButtonMouseDown;
month.CalendarLeftMouseButtonUp += Month_CalendarButtonMouseUp;
month.PointerEnter += Month_MouseEnter;
- month.PointerLeave += Month_MouseLeave;
children.Add(month);
}
}
@@ -937,17 +905,7 @@ namespace Avalonia.Controls.Primitives
}
}
}
- internal void Cell_MouseLeave(object sender, PointerEventArgs e)
- {
- if (_isMouseLeftButtonDown)
- {
- CalendarDayButton b = (CalendarDayButton)sender;
- // The button is in Pressed state. Change the state to normal.
- if (e.Pointer.Captured == b)
- e.Pointer.Capture(null);
- _lastCalendarDayButton = b;
- }
- }
+
internal void Cell_MouseLeftButtonDown(object sender, PointerPressedEventArgs e)
{
if (Owner != null)
@@ -1207,35 +1165,6 @@ namespace Avalonia.Controls.Primitives
}
}
- private void Month_MouseLeave(object sender, PointerEventArgs e)
- {
- if (_isMouseLeftButtonDownYearView)
- {
- CalendarButton b = (CalendarButton)sender;
- // The button is in Pressed state. Change the state to normal.
- if (e.Pointer.Captured == b)
- e.Pointer.Capture(null);
- //b.ReleaseMouseCapture();
-
- _lastCalendarButton = b;
- }
- }
- private void MonthView_MouseLeave(object sender, PointerEventArgs e)
- {
- if (_lastCalendarDayButton != null)
- {
- e.Pointer.Capture(_lastCalendarDayButton);
- }
- }
-
- private void YearView_MouseLeave(object sender, PointerEventArgs e)
- {
- if (_lastCalendarButton != null)
- {
- e.Pointer.Capture(_lastCalendarButton);
- }
- }
-
internal void UpdateDisabled(bool isEnabled)
{
PseudoClasses.Set(":calendardisabled", !isEnabled);
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index 3d8ab3ae48..7d4fef009d 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -101,7 +101,7 @@ namespace Avalonia.Controls
private ICommand? _command;
private bool _commandCanExecute = true;
- private Popup _popup;
+ private Popup? _popup;
///
/// Initializes static members of the class.
@@ -145,7 +145,7 @@ namespace Avalonia.Controls
{
var parent = x as Control;
return parent?.GetObservable(DefinitionBase.PrivateSharedSizeScopeProperty) ??
- Observable.Return(null);
+ Observable.Return(null);
});
this.Bind(DefinitionBase.PrivateSharedSizeScopeProperty, parentSharedSizeScope);
diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
index 6d6398bcda..a54d1ce308 100644
--- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
+++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
@@ -148,6 +148,7 @@ namespace Avalonia.Controls.Platform
{
case Key.Up:
case Key.Down:
+ {
if (item?.IsTopLevel == true)
{
if (item.HasSubMenu && !item.IsSubMenuOpen)
@@ -161,8 +162,10 @@ namespace Avalonia.Controls.Platform
goto default;
}
break;
+ }
case Key.Left:
+ {
if (item?.Parent is IMenuItem parent && !parent.IsTopLevel && parent.IsSubMenuOpen)
{
parent.Close();
@@ -174,8 +177,10 @@ namespace Avalonia.Controls.Platform
goto default;
}
break;
+ }
case Key.Right:
+ {
if (item != null && !item.IsTopLevel && item.HasSubMenu)
{
Open(item, true);
@@ -186,8 +191,10 @@ namespace Avalonia.Controls.Platform
goto default;
}
break;
+ }
case Key.Enter:
+ {
if (item != null)
{
if (!item.HasSubMenu)
@@ -202,12 +209,14 @@ namespace Avalonia.Controls.Platform
e.Handled = true;
}
break;
+ }
case Key.Escape:
- if (item?.Parent != null)
+ {
+ if (item?.Parent is IMenuElement parent)
{
- item.Parent.Close();
- item.Parent.Focus();
+ parent.Close();
+ parent.Focus();
}
else
{
@@ -216,8 +225,10 @@ namespace Avalonia.Controls.Platform
e.Handled = true;
break;
+ }
default:
+ {
var direction = e.Key.ToNavigationDirection();
if (direction.HasValue)
@@ -246,6 +257,7 @@ namespace Avalonia.Controls.Platform
}
break;
+ }
}
if (!e.Handled && item?.Parent is IMenuItem parentItem)
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index f5115a2f7c..6a6d37605d 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -77,7 +77,8 @@ namespace Avalonia.Controls.Presenters
static TextPresenter()
{
- AffectsRender(SelectionBrushProperty);
+ AffectsRender(SelectionBrushProperty, TextBlock.ForegroundProperty,
+ SelectionForegroundBrushProperty, CaretBrushProperty);
AffectsMeasure(TextProperty, PasswordCharProperty, RevealPasswordProperty,
TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty,
TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty);
diff --git a/src/Avalonia.Themes.Fluent/Accents/Base.xaml b/src/Avalonia.Themes.Fluent/Accents/Base.xaml
index 134e804c53..0e34eb3f3b 100644
--- a/src/Avalonia.Themes.Fluent/Accents/Base.xaml
+++ b/src/Avalonia.Themes.Fluent/Accents/Base.xaml
@@ -12,7 +12,7 @@
#FF0066CC
#FFFFFFFF
#FF000000
- avares://Avalonia.Themes.Fluent/Assets#Roboto
+ avares://Avalonia.Themes.Fluent/Assets#Inter
14
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf
new file mode 100644
index 0000000000..847ffd191b
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf
new file mode 100644
index 0000000000..33267cd799
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf
new file mode 100644
index 0000000000..c22eafe9fb
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf
new file mode 100644
index 0000000000..f782894eea
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf
new file mode 100644
index 0000000000..3b7e686e54
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf
new file mode 100644
index 0000000000..556e972f48
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf
new file mode 100644
index 0000000000..e49058e33d
Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Black.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Black.ttf
deleted file mode 100644
index 38f809991d..0000000000
Binary files a/src/Avalonia.Themes.Fluent/Assets/Roboto-Black.ttf and /dev/null differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Bold.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Bold.ttf
deleted file mode 100644
index 5fd9dd9eed..0000000000
Binary files a/src/Avalonia.Themes.Fluent/Assets/Roboto-Bold.ttf and /dev/null differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Light.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Light.ttf
deleted file mode 100644
index 113d545eea..0000000000
Binary files a/src/Avalonia.Themes.Fluent/Assets/Roboto-Light.ttf and /dev/null differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Medium.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Medium.ttf
deleted file mode 100644
index 98c4538462..0000000000
Binary files a/src/Avalonia.Themes.Fluent/Assets/Roboto-Medium.ttf and /dev/null differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Regular.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Regular.ttf
deleted file mode 100644
index c1c3700fe5..0000000000
Binary files a/src/Avalonia.Themes.Fluent/Assets/Roboto-Regular.ttf and /dev/null differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Thin.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Thin.ttf
deleted file mode 100644
index 04b15402d9..0000000000
Binary files a/src/Avalonia.Themes.Fluent/Assets/Roboto-Thin.ttf and /dev/null differ
diff --git a/src/Avalonia.Visuals/Animation/CompositePageTransition.cs b/src/Avalonia.Visuals/Animation/CompositePageTransition.cs
new file mode 100644
index 0000000000..9489914c97
--- /dev/null
+++ b/src/Avalonia.Visuals/Animation/CompositePageTransition.cs
@@ -0,0 +1,61 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Defines a composite page transition that can be used to combine multiple transitions.
+ ///
+ ///
+ ///
+ /// Instantiate the in XAML and initialize the
+ /// property in order to have many animations triggered at once.
+ /// For example, you can combine and .
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// ]]>
+ ///
+ ///
+ ///
+ public class CompositePageTransition : IPageTransition
+ {
+ ///
+ /// Gets or sets the transitions to be executed. Can be defined from XAML.
+ ///
+ [Content]
+ public List PageTransitions { get; set; } = new List();
+
+ ///
+ /// Starts the animation.
+ ///
+ ///
+ /// The control that is being transitioned away from. May be null.
+ ///
+ ///
+ /// The control that is being transitioned to. May be null.
+ ///
+ ///
+ /// Defines the direction of the transition.
+ ///
+ ///
+ /// A that tracks the progress of the animation.
+ ///
+ public Task Start(Visual from, Visual to, bool forward)
+ {
+ var transitionTasks = PageTransitions
+ .Select(transition => transition.Start(from, to, forward))
+ .ToList();
+ return Task.WhenAll(transitionTasks);
+ }
+ }
+}
diff --git a/src/Avalonia.Visuals/Animation/CrossFade.cs b/src/Avalonia.Visuals/Animation/CrossFade.cs
index 640f401418..0615b854da 100644
--- a/src/Avalonia.Visuals/Animation/CrossFade.cs
+++ b/src/Avalonia.Visuals/Animation/CrossFade.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Avalonia.Animation.Easings;
using Avalonia.Styling;
using Avalonia.VisualTree;
@@ -74,14 +75,26 @@ namespace Avalonia.Animation
///
public TimeSpan Duration
{
- get
- {
- return _fadeOutAnimation.Duration;
- }
- set
- {
- _fadeOutAnimation.Duration = _fadeInAnimation.Duration = value;
- }
+ get => _fadeOutAnimation.Duration;
+ set => _fadeOutAnimation.Duration = _fadeInAnimation.Duration = value;
+ }
+
+ ///
+ /// Gets or sets element entrance easing.
+ ///
+ public Easing FadeInEasing
+ {
+ get => _fadeInAnimation.Easing;
+ set => _fadeInAnimation.Easing = value;
+ }
+
+ ///
+ /// Gets or sets element exit easing.
+ ///
+ public Easing FadeOutEasing
+ {
+ get => _fadeOutAnimation.Easing;
+ set => _fadeOutAnimation.Easing = value;
}
///
diff --git a/src/Avalonia.Visuals/Animation/PageSlide.cs b/src/Avalonia.Visuals/Animation/PageSlide.cs
index 501c8c0ba4..dd5d598e12 100644
--- a/src/Avalonia.Visuals/Animation/PageSlide.cs
+++ b/src/Avalonia.Visuals/Animation/PageSlide.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Avalonia.Animation.Easings;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.VisualTree;
@@ -48,6 +49,16 @@ namespace Avalonia.Animation
/// Gets the duration of the animation.
///
public SlideAxis Orientation { get; set; }
+
+ ///
+ /// Gets or sets element entrance easing.
+ ///
+ public Easing SlideInEasing { get; set; } = new LinearEasing();
+
+ ///
+ /// Gets or sets element exit easing.
+ ///
+ public Easing SlideOutEasing { get; set; } = new LinearEasing();
///
/// Starts the animation.
@@ -75,18 +86,12 @@ namespace Avalonia.Animation
{
var animation = new Animation
{
- Children =
+ Easing = SlideOutEasing,
+ Children =
{
new KeyFrame
{
- Setters =
- {
- new Setter
- {
- Property = translateProperty,
- Value = 0d
- }
- },
+ Setters = { new Setter { Property = translateProperty, Value = 0d } },
Cue = new Cue(0d)
},
new KeyFrame
@@ -100,10 +105,10 @@ namespace Avalonia.Animation
}
},
Cue = new Cue(1d)
- }
- }
+ }
+ },
+ Duration = Duration
};
- animation.Duration = Duration;
tasks.Add(animation.RunAsync(from));
}
@@ -112,9 +117,9 @@ namespace Avalonia.Animation
to.IsVisible = true;
var animation = new Animation
{
+ Easing = SlideInEasing,
Children =
{
-
new KeyFrame
{
Setters =
@@ -129,19 +134,12 @@ namespace Avalonia.Animation
},
new KeyFrame
{
- Setters =
- {
- new Setter
- {
- Property = translateProperty,
- Value = 0d
- }
- },
+ Setters = { new Setter { Property = translateProperty, Value = 0d } },
Cue = new Cue(1d)
}
- }
+ },
+ Duration = Duration
};
- animation.Duration = Duration;
tasks.Add(animation.RunAsync(to));
}
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 98528a128a..05a8daaec8 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -583,14 +583,45 @@ namespace Avalonia.Skia
var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint();
var radius = (float)(radialGradient.Radius * targetSize.Width);
- // TODO: There is no SetAlpha in SkiaSharp
- //paint.setAlpha(128);
+ var origin = radialGradient.GradientOrigin.ToPixels(targetSize).ToSKPoint();
- // would be nice to cache these shaders possibly?
- using (var shader =
- SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode))
+ if (origin.Equals(center))
{
- paintWrapper.Paint.Shader = shader;
+ // when the origin is the same as the center the Skia RadialGradient acts the same as D2D
+ using (var shader =
+ SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode))
+ {
+ paintWrapper.Paint.Shader = shader;
+ }
+ }
+ else
+ {
+ // when the origin is different to the center use a two point ConicalGradient to match the behaviour of D2D
+
+ // reverse the order of the stops to match D2D
+ var reversedColors = new SKColor[stopColors.Length];
+ Array.Copy(stopColors, reversedColors, stopColors.Length);
+ Array.Reverse(reversedColors);
+
+ // and then reverse the reference point of the stops
+ var reversedStops = new float[stopOffsets.Length];
+ for (var i = 0; i < stopOffsets.Length; i++)
+ {
+ reversedStops[i] = stopOffsets[i];
+ if (reversedStops[i] > 0 && reversedStops[i] < 1)
+ {
+ reversedStops[i] = Math.Abs(1 - stopOffsets[i]);
+ }
+ }
+
+ // compose with a background colour of the final stop to match D2D's behaviour of filling with the final color
+ using (var shader = SKShader.CreateCompose(
+ SKShader.CreateColor(reversedColors[0]),
+ SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode)
+ ))
+ {
+ paintWrapper.Paint.Shader = shader;
+ }
}
break;
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
index 25a34561fc..a03e1ffc22 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
@@ -200,6 +200,10 @@ namespace Avalonia.Win32
DipFromLParam(lParam), GetMouseModifiers(wParam));
break;
}
+ // Mouse capture is lost
+ case WindowsMessage.WM_CANCELMODE:
+ _mouseDevice.Capture(null);
+ break;
case WindowsMessage.WM_MOUSEMOVE:
{
diff --git a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
index 9beb860bee..2941b8dc34 100644
--- a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
+++ b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
public RadialGradientBrushTests() : base(@"Media\RadialGradientBrush")
{
}
-
+
[Fact]
public async Task RadialGradientBrush_RedBlue()
{
@@ -43,5 +43,127 @@ namespace Avalonia.Direct2D1.RenderTests.Media
await RenderToFile(target);
CompareImages();
}
+
+ ///
+ /// Tests using a GradientOrigin that falls inside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedBlue_Offset_Inside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.25, 0.25, RelativeUnit.Relative)
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ ///
+ /// Tests using a GradientOrigin that falls outside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedBlue_Offset_Outside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.1, 0.1, RelativeUnit.Relative)
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ ///
+ /// Tests using a GradientOrigin that falls inside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedGreenBlue_Offset_Inside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Green, Offset = 0.5 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.25, 0.25, RelativeUnit.Relative),
+ Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative),
+ Radius = 0.5
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ ///
+ /// Tests using a GradientOrigin that falls outside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedGreenBlue_Offset_Outside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Green, Offset = 0.25 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.1, 0.1, RelativeUnit.Relative),
+ Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative),
+ Radius = 0.5
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
}
}
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..4d690abee5
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..667aa9151e
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..1d660f79d1
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..ea1009b54a
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..4d690abee5
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..667aa9151e
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..1d660f79d1
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..ea1009b54a
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png differ