diff --git a/src/Avalonia.Visuals/Media/Brush.cs b/src/Avalonia.Visuals/Media/Brush.cs index eef6e1a43c..8ba7c1be04 100644 --- a/src/Avalonia.Visuals/Media/Brush.cs +++ b/src/Avalonia.Visuals/Media/Brush.cs @@ -10,7 +10,7 @@ namespace Avalonia.Media /// Describes how an area is painted. /// [TypeConverter(typeof(BrushConverter))] - public abstract class Brush : AvaloniaObject, IBrush + public abstract class Brush : AvaloniaObject, IMutableBrush { /// /// Defines the property. @@ -18,6 +18,9 @@ namespace Avalonia.Media public static readonly StyledProperty OpacityProperty = AvaloniaProperty.Register(nameof(Opacity), 1.0); + /// + public event EventHandler Changed; + /// /// Gets or sets the opacity of the brush. /// @@ -50,5 +53,36 @@ namespace Avalonia.Media throw new FormatException($"Invalid brush string: '{s}'."); } + + /// + public abstract IBrush ToImmutable(); + + /// + /// Marks a property as affecting the brush's visual representation. + /// + /// The properties. + /// + /// After a call to this method in a brush's static constructor, any change to the + /// property will cause the event to be raised on the brush. + /// + protected static void AffectsRender(params AvaloniaProperty[] properties) + where T : Brush + { + void Invalidate(AvaloniaPropertyChangedEventArgs e) + { + (e.Sender as T)?.RaiseChanged(EventArgs.Empty); + } + + foreach (var property in properties) + { + property.Changed.Subscribe(Invalidate); + } + } + + /// + /// Raises the event. + /// + /// The event args. + protected void RaiseChanged(EventArgs e) => Changed?.Invoke(this, e); } } diff --git a/src/Avalonia.Visuals/Media/GradientBrush.cs b/src/Avalonia.Visuals/Media/GradientBrush.cs index 41c3afc8c3..c123813cee 100644 --- a/src/Avalonia.Visuals/Media/GradientBrush.cs +++ b/src/Avalonia.Visuals/Media/GradientBrush.cs @@ -1,7 +1,11 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using Avalonia.Collections; using Avalonia.Metadata; namespace Avalonia.Media @@ -20,35 +24,74 @@ namespace Avalonia.Media /// /// Defines the property. /// - public static readonly StyledProperty> GradientStopsProperty = - AvaloniaProperty.Register>(nameof(GradientStops)); + public static readonly StyledProperty GradientStopsProperty = + AvaloniaProperty.Register(nameof(GradientStops)); + + private IDisposable _gradientStopsSubscription; + + static GradientBrush() + { + GradientStopsProperty.Changed.Subscribe(GradientStopsChanged); + AffectsRender(SpreadMethodProperty); + } /// /// Initializes a new instance of the class. /// public GradientBrush() { - this.GradientStops = new List(); + this.GradientStops = new GradientStops(); } - /// - /// Gets or sets the brush's spread method that defines how to draw a gradient that - /// doesn't fill the bounds of the destination control. - /// + /// public GradientSpreadMethod SpreadMethod { get { return GetValue(SpreadMethodProperty); } set { SetValue(SpreadMethodProperty, value); } } - /// - /// Gets or sets the brush's gradient stops. - /// + /// [Content] - public IList GradientStops + public GradientStops GradientStops { get { return GetValue(GradientStopsProperty); } set { SetValue(GradientStopsProperty, value); } } + + /// + IReadOnlyList IGradientBrush.GradientStops => GradientStops; + + private static void GradientStopsChanged(AvaloniaPropertyChangedEventArgs e) + { + if (e.Sender is GradientBrush brush) + { + var oldValue = (GradientStops)e.OldValue; + var newValue = (GradientStops)e.NewValue; + + if (oldValue != null) + { + oldValue.CollectionChanged -= brush.GradientStopsChanged; + brush._gradientStopsSubscription.Dispose(); + } + + if (newValue != null) + { + newValue.CollectionChanged += brush.GradientStopsChanged; + brush._gradientStopsSubscription = newValue.TrackItemPropertyChanged(brush.GradientStopChanged); + } + + brush.RaiseChanged(EventArgs.Empty); + } + } + + private void GradientStopsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + RaiseChanged(EventArgs.Empty); + } + + private void GradientStopChanged(Tuple e) + { + RaiseChanged(EventArgs.Empty); + } } } diff --git a/src/Avalonia.Visuals/Media/GradientStop.cs b/src/Avalonia.Visuals/Media/GradientStop.cs index 78dd32a18a..00d96a0b3c 100644 --- a/src/Avalonia.Visuals/Media/GradientStop.cs +++ b/src/Avalonia.Visuals/Media/GradientStop.cs @@ -4,10 +4,22 @@ namespace Avalonia.Media { /// - /// GradientStop + /// Describes the location and color of a transition point in a gradient. /// - public sealed class GradientStop + public sealed class GradientStop : AvaloniaObject, IGradientStop { + /// + /// Describes the property. + /// + public static StyledProperty OffsetProperty = + AvaloniaProperty.Register(nameof(Offset)); + + /// + /// Describes the property. + /// + public static StyledProperty ColorProperty = + AvaloniaProperty.Register(nameof(Color)); + /// /// Initializes a new instance of the class. /// @@ -24,16 +36,18 @@ namespace Avalonia.Media Offset = offset; } - // TODO: Make these dependency properties. - - /// - /// The offset - /// - public double Offset { get; set; } + /// + public double Offset + { + get => GetValue(OffsetProperty); + set => SetValue(OffsetProperty, value); + } - /// - /// The color - /// - public Color Color { get; set; } + /// + public Color Color + { + get => GetValue(ColorProperty); + set => SetValue(ColorProperty, value); + } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/GradientStops.cs b/src/Avalonia.Visuals/Media/GradientStops.cs new file mode 100644 index 0000000000..efc11bacd6 --- /dev/null +++ b/src/Avalonia.Visuals/Media/GradientStops.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using Avalonia.Collections; +using Avalonia.Media.Immutable; + +namespace Avalonia.Media +{ + /// + /// A collection of s. + /// + public class GradientStops : AvaloniaList + { + public GradientStops() + { + ResetBehavior = ResetBehavior.Remove; + } + + public IReadOnlyList ToImmutable() + { + return this.Select(x => new ImmutableGradientStop(x.Offset, x.Color)).ToList(); + } + } +} diff --git a/src/Avalonia.Visuals/Media/IGradientBrush.cs b/src/Avalonia.Visuals/Media/IGradientBrush.cs index 390ce6ee5b..18db0af660 100644 --- a/src/Avalonia.Visuals/Media/IGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/IGradientBrush.cs @@ -10,7 +10,7 @@ namespace Avalonia.Media /// /// Gets the brush's gradient stops. /// - IList GradientStops { get; } + IReadOnlyList GradientStops { get; } /// /// Gets the brush's spread method that defines how to draw a gradient that doesn't fill @@ -18,4 +18,4 @@ namespace Avalonia.Media /// GradientSpreadMethod SpreadMethod { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/IGradientStop.cs b/src/Avalonia.Visuals/Media/IGradientStop.cs new file mode 100644 index 0000000000..22eb9df60d --- /dev/null +++ b/src/Avalonia.Visuals/Media/IGradientStop.cs @@ -0,0 +1,18 @@ +namespace Avalonia.Media +{ + /// + /// Describes the location and color of a transition point in a gradient. + /// + public interface IGradientStop + { + /// + /// Gets the gradient stop color. + /// + Color Color { get; } + + /// + /// Gets the gradient stop offset. + /// + double Offset { get; } + } +} diff --git a/src/Avalonia.Visuals/Media/IMutableBrush.cs b/src/Avalonia.Visuals/Media/IMutableBrush.cs index 39dd8b80c4..762731a6a8 100644 --- a/src/Avalonia.Visuals/Media/IMutableBrush.cs +++ b/src/Avalonia.Visuals/Media/IMutableBrush.cs @@ -1,10 +1,17 @@ -namespace Avalonia.Media +using System; + +namespace Avalonia.Media { /// /// Represents a mutable brush which can return an immutable clone of itself. /// public interface IMutableBrush : IBrush { + /// + /// Raised when the brush changes visually. + /// + event EventHandler Changed; + /// /// Creates an immutable clone of the brush. /// diff --git a/src/Avalonia.Visuals/Media/ImageBrush.cs b/src/Avalonia.Visuals/Media/ImageBrush.cs index fa491ed3e1..8b42a51d9f 100644 --- a/src/Avalonia.Visuals/Media/ImageBrush.cs +++ b/src/Avalonia.Visuals/Media/ImageBrush.cs @@ -2,13 +2,14 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using Avalonia.Media.Imaging; +using Avalonia.Media.Immutable; namespace Avalonia.Media { /// /// Paints an area with an . /// - public class ImageBrush : TileBrush, IImageBrush, IMutableBrush + public class ImageBrush : TileBrush, IImageBrush { /// /// Defines the property. @@ -16,6 +17,11 @@ namespace Avalonia.Media public static readonly StyledProperty SourceProperty = AvaloniaProperty.Register(nameof(Source)); + static ImageBrush() + { + AffectsRender(SourceProperty); + } + /// /// Initializes a new instance of the class. /// @@ -42,9 +48,9 @@ namespace Avalonia.Media } /// - IBrush IMutableBrush.ToImmutable() + public override IBrush ToImmutable() { - return new Immutable.ImmutableImageBrush(this); + return new ImmutableImageBrush(this); } } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs index 6664a2b30e..1f6e3bbcfd 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Avalonia.Media.Immutable { @@ -15,7 +14,7 @@ namespace Avalonia.Media.Immutable /// The opacity of the brush. /// The spread method. protected ImmutableGradientBrush( - IList gradientStops, + IReadOnlyList gradientStops, double opacity, GradientSpreadMethod spreadMethod) { @@ -28,14 +27,14 @@ namespace Avalonia.Media.Immutable /// Initializes a new instance of the class. /// /// The brush from which this brush's properties should be copied. - protected ImmutableGradientBrush(IGradientBrush source) - : this(source.GradientStops.ToList(), source.Opacity, source.SpreadMethod) + protected ImmutableGradientBrush(GradientBrush source) + : this(source.GradientStops.ToImmutable(), source.Opacity, source.SpreadMethod) { } /// - public IList GradientStops { get; } + public IReadOnlyList GradientStops { get; } /// public double Opacity { get; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientStop.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientStop.cs new file mode 100644 index 0000000000..f3e2e52fd0 --- /dev/null +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientStop.cs @@ -0,0 +1,20 @@ +namespace Avalonia.Media.Immutable +{ + /// + /// Describes the location and color of a transition point in a gradient. + /// + public class ImmutableGradientStop : IGradientStop + { + public ImmutableGradientStop(double offset, Color color) + { + Offset = offset; + Color = color; + } + + /// + public double Offset { get; } + + /// + public Color Color { get; } + } +} diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs index 142eb34625..912d77d763 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs @@ -16,7 +16,7 @@ namespace Avalonia.Media.Immutable /// The start point for the gradient. /// The end point for the gradient. public ImmutableLinearGradientBrush( - IList gradientStops, + IReadOnlyList gradientStops, double opacity = 1, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? startPoint = null, @@ -31,7 +31,7 @@ namespace Avalonia.Media.Immutable /// Initializes a new instance of the class. /// /// The brush from which this brush's properties should be copied. - public ImmutableLinearGradientBrush(ILinearGradientBrush source) + public ImmutableLinearGradientBrush(LinearGradientBrush source) : base(source) { StartPoint = source.StartPoint; diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs index f36a1cd2de..e26fbab5f5 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs @@ -21,7 +21,7 @@ namespace Avalonia.Media.Immutable /// The horizontal and vertical radius of the outermost circle of the radial gradient. /// public ImmutableRadialGradientBrush( - IList gradientStops, + IReadOnlyList gradientStops, double opacity = 1, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, @@ -38,7 +38,7 @@ namespace Avalonia.Media.Immutable /// Initializes a new instance of the class. /// /// The brush from which this brush's properties should be copied. - public ImmutableRadialGradientBrush(IRadialGradientBrush source) + public ImmutableRadialGradientBrush(RadialGradientBrush source) : base(source) { Center = source.Center; diff --git a/src/Avalonia.Visuals/Media/LinearGradientBrush.cs b/src/Avalonia.Visuals/Media/LinearGradientBrush.cs index d092bebf0f..14adc0e0cd 100644 --- a/src/Avalonia.Visuals/Media/LinearGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/LinearGradientBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Media.Immutable; + namespace Avalonia.Media { /// /// A brush that draws with a linear gradient. /// - public sealed class LinearGradientBrush : GradientBrush, ILinearGradientBrush, IMutableBrush + public sealed class LinearGradientBrush : GradientBrush, ILinearGradientBrush { /// /// Defines the property. @@ -24,6 +26,11 @@ namespace Avalonia.Media nameof(EndPoint), RelativePoint.BottomRight); + static LinearGradientBrush() + { + AffectsRender(StartPointProperty, EndPointProperty); + } + /// /// Gets or sets the start point for the gradient. /// @@ -43,9 +50,9 @@ namespace Avalonia.Media } /// - IBrush IMutableBrush.ToImmutable() + public override IBrush ToImmutable() { - return new Immutable.ImmutableLinearGradientBrush(this); + return new ImmutableLinearGradientBrush(this); } } } diff --git a/src/Avalonia.Visuals/Media/RadialGradientBrush.cs b/src/Avalonia.Visuals/Media/RadialGradientBrush.cs index 003e2e05f9..589cd83ca1 100644 --- a/src/Avalonia.Visuals/Media/RadialGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/RadialGradientBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Media.Immutable; + namespace Avalonia.Media { /// /// Paints an area with a radial gradient. /// - public sealed class RadialGradientBrush : GradientBrush, IRadialGradientBrush, IMutableBrush + public sealed class RadialGradientBrush : GradientBrush, IRadialGradientBrush { /// /// Defines the property. @@ -63,9 +65,9 @@ namespace Avalonia.Media } /// - IBrush IMutableBrush.ToImmutable() + public override IBrush ToImmutable() { - return new Immutable.ImmutableRadialGradientBrush(this); + return new ImmutableRadialGradientBrush(this); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/SolidColorBrush.cs b/src/Avalonia.Visuals/Media/SolidColorBrush.cs index d84e407cb4..32b87df56b 100644 --- a/src/Avalonia.Visuals/Media/SolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/SolidColorBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Media.Immutable; + namespace Avalonia.Media { /// /// Fills an area with a solid color. /// - public class SolidColorBrush : Brush, ISolidColorBrush, IMutableBrush + public class SolidColorBrush : Brush, ISolidColorBrush { /// /// Defines the property. @@ -14,6 +16,11 @@ namespace Avalonia.Media public static readonly StyledProperty ColorProperty = AvaloniaProperty.Register(nameof(Color)); + static SolidColorBrush() + { + AffectsRender(ColorProperty); + } + /// /// Initializes a new instance of the class. /// @@ -75,9 +82,9 @@ namespace Avalonia.Media } /// - IBrush IMutableBrush.ToImmutable() + public override IBrush ToImmutable() { - return new Immutable.ImmutableSolidColorBrush(this); + return new ImmutableSolidColorBrush(this); } } } diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 2033754137..47f20fa285 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -79,6 +79,13 @@ namespace Avalonia.Media static TileBrush() { + AffectsRender( + AlignmentXProperty, + AlignmentYProperty, + DestinationRectProperty, + SourceRectProperty, + StretchProperty, + TileModeProperty); RenderOptions.BitmapInterpolationModeProperty.OverrideDefaultValue(BitmapInterpolationMode.Default); } diff --git a/src/Avalonia.Visuals/Media/VisualBrush.cs b/src/Avalonia.Visuals/Media/VisualBrush.cs index 435f4ba1b1..963ba8f4a1 100644 --- a/src/Avalonia.Visuals/Media/VisualBrush.cs +++ b/src/Avalonia.Visuals/Media/VisualBrush.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Media.Immutable; using Avalonia.VisualTree; namespace Avalonia.Media @@ -8,7 +9,7 @@ namespace Avalonia.Media /// /// Paints an area with an . /// - public class VisualBrush : TileBrush, IVisualBrush, IMutableBrush + public class VisualBrush : TileBrush, IVisualBrush { /// /// Defines the property. @@ -16,6 +17,11 @@ namespace Avalonia.Media public static readonly StyledProperty VisualProperty = AvaloniaProperty.Register(nameof(Visual)); + static VisualBrush() + { + AffectsRender(VisualProperty); + } + /// /// Initializes a new instance of the class. /// @@ -42,9 +48,9 @@ namespace Avalonia.Media } /// - IBrush IMutableBrush.ToImmutable() + public override IBrush ToImmutable() { - return new Immutable.ImmutableVisualBrush(this); + return new ImmutableVisualBrush(this); } } } diff --git a/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs b/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs index 8356e78cc3..6a01536b12 100644 --- a/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs +++ b/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs @@ -124,7 +124,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new[] + GradientStops = { new GradientStop(Color.FromUInt32(0xffffffff), 0), new GradientStop(Color.FromUInt32(0x00ffffff), 1) diff --git a/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs index 656e77fc31..a0d6f1e423 100644 --- a/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs @@ -36,7 +36,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media { StartPoint = new RelativePoint(0, 0.5, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 0.5, RelativeUnit.Relative), - GradientStops = new[] + GradientStops = { new GradientStop { Color = Colors.Red, Offset = 0 }, new GradientStop { Color = Colors.Blue, Offset = 1 } @@ -63,7 +63,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media { StartPoint = new RelativePoint(0.5, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0.5, 1, RelativeUnit.Relative), - GradientStops = new[] + GradientStops = { new GradientStop { Color = Colors.Red, Offset = 0 }, new GradientStop { Color = Colors.Blue, Offset = 1 } diff --git a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs index 0017feb106..bd1d26ce70 100644 --- a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs @@ -34,7 +34,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media { Background = new RadialGradientBrush { - GradientStops = new[] + GradientStops = { new GradientStop { Color = Colors.Red, Offset = 0 }, new GradientStop { Color = Colors.Blue, Offset = 1 } diff --git a/tests/Avalonia.RenderTests/OpacityMaskTests.cs b/tests/Avalonia.RenderTests/OpacityMaskTests.cs index 4edf4daa13..2f01b03db6 100644 --- a/tests/Avalonia.RenderTests/OpacityMaskTests.cs +++ b/tests/Avalonia.RenderTests/OpacityMaskTests.cs @@ -29,7 +29,7 @@ namespace Avalonia.Direct2D1.RenderTests { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new List + GradientStops = { new GradientStop(Color.FromUInt32(0xffffffff), 0), new GradientStop(Color.FromUInt32(0x00ffffff), 1) @@ -65,7 +65,7 @@ namespace Avalonia.Direct2D1.RenderTests { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new List + GradientStops = { new GradientStop(Color.FromUInt32(0xffffffff), 0), new GradientStop(Color.FromUInt32(0x00ffffff), 1) diff --git a/tests/Avalonia.Visuals.UnitTests/Media/ImageBrushTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/ImageBrushTests.cs new file mode 100644 index 0000000000..f843a6e333 --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/Media/ImageBrushTests.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Moq; +using Xunit; + +namespace Avalonia.Visuals.UnitTests.Media +{ + public class ImageBrushTests + { + [Fact] + public void Changing_Source_Raises_Changed() + { + var bitmap1 = Mock.Of(); + var bitmap2 = Mock.Of(); + var target = new ImageBrush(bitmap1); + var raised = false; + + target.Changed += (s, e) => raised = true; + target.Source = bitmap2; + + Assert.True(raised); + } + } +} diff --git a/tests/Avalonia.Visuals.UnitTests/Media/LinearGradientBrushTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/LinearGradientBrushTests.cs new file mode 100644 index 0000000000..62f53108e6 --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/Media/LinearGradientBrushTests.cs @@ -0,0 +1,86 @@ +using System; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Moq; +using Xunit; + +namespace Avalonia.Visuals.UnitTests.Media +{ + public class LinearGradientBrushTests + { + [Fact] + public void Changing_StartPoint_Raises_Changed() + { + var bitmap1 = Mock.Of(); + var bitmap2 = Mock.Of(); + var target = new LinearGradientBrush(); + var raised = false; + + target.StartPoint = new RelativePoint(); + target.Changed += (s, e) => raised = true; + target.StartPoint = new RelativePoint(10, 10, RelativeUnit.Absolute); + + Assert.True(raised); + } + + [Fact] + public void Changing_EndPoint_Raises_Changed() + { + var bitmap1 = Mock.Of(); + var bitmap2 = Mock.Of(); + var target = new LinearGradientBrush(); + var raised = false; + + target.EndPoint = new RelativePoint(); + target.Changed += (s, e) => raised = true; + target.EndPoint = new RelativePoint(10, 10, RelativeUnit.Absolute); + + Assert.True(raised); + } + + [Fact] + public void Changing_GradientStops_Raises_Changed() + { + var bitmap1 = Mock.Of(); + var bitmap2 = Mock.Of(); + var target = new LinearGradientBrush(); + var raised = false; + + target.GradientStops = new GradientStops { new GradientStop(Colors.Red, 0) }; + target.Changed += (s, e) => raised = true; + target.GradientStops = new GradientStops { new GradientStop(Colors.Green, 0) }; + + Assert.True(raised); + } + + [Fact] + public void Adding_GradientStop_Raises_Changed() + { + var bitmap1 = Mock.Of(); + var bitmap2 = Mock.Of(); + var target = new LinearGradientBrush(); + var raised = false; + + target.GradientStops = new GradientStops { new GradientStop(Colors.Red, 0) }; + target.Changed += (s, e) => raised = true; + target.GradientStops.Add(new GradientStop(Colors.Green, 1)); + + Assert.True(raised); + } + + [Fact] + public void Changing_GradientStop_Offset_Raises_Changed() + { + var bitmap1 = Mock.Of(); + var bitmap2 = Mock.Of(); + var target = new LinearGradientBrush(); + var raised = false; + + target.GradientStops = new GradientStops { new GradientStop(Colors.Red, 0) }; + target.Changed += (s, e) => raised = true; + target.GradientStops[0].Offset = 0.5; + + Assert.True(raised); + } + } +} diff --git a/tests/Avalonia.Visuals.UnitTests/Media/SolidColorBrushTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/SolidColorBrushTests.cs new file mode 100644 index 0000000000..4e87b7081d --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/Media/SolidColorBrushTests.cs @@ -0,0 +1,21 @@ +using System; +using Avalonia.Media; +using Xunit; + +namespace Avalonia.Visuals.UnitTests.Media +{ + public class SolidColorBrushTests + { + [Fact] + public void Changing_Color_Raises_Changed() + { + var target = new SolidColorBrush(Colors.Red); + var raised = false; + + target.Changed += (s, e) => raised = true; + target.Color = Colors.Green; + + Assert.True(raised); + } + } +}