committed by
GitHub
55 changed files with 2165 additions and 546 deletions
@ -1,7 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="HarfBuzzSharp" Version="2.8.2-preview.254" /> |
<PackageReference Include="HarfBuzzSharp" Version="2.8.2" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2-preview.254" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2" /> |
||||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2-preview.254"/> |
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,7 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="SkiaSharp" Version="2.88.0-preview.254" /> |
<PackageReference Include="SkiaSharp" Version="2.88.0" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.0-preview.254" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.0" /> |
||||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.0-preview.254"/> |
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.0" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -0,0 +1,210 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="700" |
||||
|
x:Class="RenderDemo.Pages.Transform3DPage"> |
||||
|
<UserControl.Styles> |
||||
|
<Styles> |
||||
|
<Styles.Resources> |
||||
|
<Template x:Key="TestContent"> |
||||
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,*" Margin="5"> |
||||
|
<TextBlock>I'm a text</TextBlock> |
||||
|
<Button Grid.Row="0" Grid.Column="1" Content="A Button"></Button> |
||||
|
<Slider Grid.Row="1" |
||||
|
Grid.Column="0" |
||||
|
Grid.ColumnSpan="2" |
||||
|
Value="{Binding Depth}" |
||||
|
Minimum="100" |
||||
|
Maximum="300" /> |
||||
|
</Grid> |
||||
|
</Template> |
||||
|
</Styles.Resources> |
||||
|
</Styles> |
||||
|
<Style Selector="Border.Test"> |
||||
|
<Setter Property="Width" Value="200" /> |
||||
|
<Setter Property="Height" Value="200" /> |
||||
|
<Setter Property="Child" Value="{StaticResource TestContent}" /> |
||||
|
<Setter Property="BorderThickness" Value="2" /> |
||||
|
<Setter Property="BorderBrush" Value="Black" /> |
||||
|
<Setter Property="Grid.ColumnSpan" Value="2" /> |
||||
|
</Style> |
||||
|
<Style Selector="TextBlock, Label, Slider"> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
<Setter Property="Margin" Value="10,0,10,0" /> |
||||
|
</Style> |
||||
|
<Style Selector="Border TextBlock"> |
||||
|
<Setter Property="Foreground" Value="White" /> |
||||
|
</Style> |
||||
|
<Style Selector="Border Button"> |
||||
|
<Setter Property="Background" Value="White"></Setter> |
||||
|
<Setter Property="Foreground" Value="Black" /> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="Border#B1"> |
||||
|
<Style.Animations> |
||||
|
<Animation Duration="0:0:10" |
||||
|
IterationCount="Infinite"> |
||||
|
<KeyFrame Cue="0%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="0" /> |
||||
|
<Setter Property="ZIndex" Value="4" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="25%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="90" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="100%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="360" /> |
||||
|
<Setter Property="ZIndex" Value="4" /> |
||||
|
</KeyFrame> |
||||
|
</Animation> |
||||
|
</Style.Animations> |
||||
|
</Style> |
||||
|
<Style Selector="Border#B2"> |
||||
|
<Style.Animations> |
||||
|
<Animation Duration="0:0:10" |
||||
|
IterationCount="Infinite"> |
||||
|
<KeyFrame Cue="0%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="90" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="25%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="180" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="75%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="360" /> |
||||
|
<Setter Property="ZIndex" Value="4" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="100%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="450" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
</Animation> |
||||
|
</Style.Animations> |
||||
|
</Style> |
||||
|
<Style Selector="Border#B3"> |
||||
|
<Style.Animations> |
||||
|
<Animation Duration="0:0:10" |
||||
|
IterationCount="Infinite"> |
||||
|
<KeyFrame Cue="0%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="180" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="50%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="360" /> |
||||
|
<Setter Property="ZIndex" Value="4" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="75%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="450" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="100%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="540" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
</Animation> |
||||
|
</Style.Animations> |
||||
|
</Style> |
||||
|
<Style Selector="Border#B4"> |
||||
|
<Style.Animations> |
||||
|
<Animation Duration="0:0:10" |
||||
|
IterationCount="Infinite"> |
||||
|
<KeyFrame Cue="0%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="270" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="25%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="360" /> |
||||
|
<Setter Property="ZIndex" Value="4" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="50%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="450" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
<KeyFrame Cue="100%"> |
||||
|
<Setter Property="Rotate3DTransform.AngleX" Value="630" /> |
||||
|
<Setter Property="ZIndex" Value="1" /> |
||||
|
</KeyFrame> |
||||
|
</Animation> |
||||
|
</Style.Animations> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<Grid ColumnDefinitions="Auto,*,Auto,*" RowDefinitions="*, Auto, Auto, Auto, Auto, Auto, Auto, Auto"> |
||||
|
<Grid.Clock> |
||||
|
<Clock /> |
||||
|
</Grid.Clock> |
||||
|
<Border Name="B1" Background="DarkRed" Classes="Test"> |
||||
|
<Border.RenderTransform> |
||||
|
<Rotate3DTransform CenterZ="-100" |
||||
|
Depth="{Binding Depth}" /> |
||||
|
</Border.RenderTransform> |
||||
|
</Border> |
||||
|
<Border Name="B2" Grid.Row="0" Grid.Column="0" Classes="Test" Background="DarkGreen"> |
||||
|
<Border.RenderTransform> |
||||
|
<Rotate3DTransform CenterZ="-100" |
||||
|
Depth="{Binding Depth}" /> |
||||
|
</Border.RenderTransform> |
||||
|
</Border> |
||||
|
<Border Name="B3" Grid.Row="0" Grid.Column="0" Classes="Test" Background="DarkBlue"> |
||||
|
<Border.RenderTransform> |
||||
|
<Rotate3DTransform CenterZ="-100" |
||||
|
Depth="{Binding Depth}" /> |
||||
|
</Border.RenderTransform> |
||||
|
</Border> |
||||
|
<Border Name="B4" Grid.Row="0" Grid.Column="0" Classes="Test" Background="Orange"> |
||||
|
<Border.RenderTransform> |
||||
|
<Rotate3DTransform CenterZ="-100" |
||||
|
Depth="{Binding Depth}" /> |
||||
|
</Border.RenderTransform> |
||||
|
</Border> |
||||
|
|
||||
|
<Label Grid.Column="0" Grid.Row="1">Depth: </Label> |
||||
|
<Slider Grid.Column="1" Grid.Row="1" Value="{Binding Depth}" Minimum="100" Maximum="300" /> |
||||
|
|
||||
|
<Border Grid.Row="0" Grid.Column="2" Classes="Test" ZIndex="-2"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%"> |
||||
|
<GradientStop Offset="0" Color="Red" /> |
||||
|
<GradientStop Offset="1" Color="Blue" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<Border.Styles> |
||||
|
<Style Selector="Label"> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="Slider"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
</Style> |
||||
|
</Border.Styles> |
||||
|
<Border.RenderTransform> |
||||
|
<Rotate3DTransform Depth="{Binding Depth}" |
||||
|
CenterX="{Binding CenterX}" |
||||
|
CenterY="{Binding CenterY}" |
||||
|
CenterZ="{Binding CenterZ}" |
||||
|
AngleX="{Binding AngleX}" |
||||
|
AngleY="{Binding AngleY}" |
||||
|
AngleZ="{Binding AngleZ}" /> |
||||
|
</Border.RenderTransform> |
||||
|
</Border> |
||||
|
|
||||
|
<Label Grid.Row="1" Grid.Column="2">Center X: </Label> |
||||
|
<Slider Grid.Row="1" Grid.Column="3" Value="{Binding CenterX}" Minimum="-100" Maximum="100" /> |
||||
|
|
||||
|
<Label Grid.Row="2" Grid.Column="2">Center Y: </Label> |
||||
|
<Slider Grid.Row="2" Grid.Column="3" Value="{Binding CenterY}" Minimum="-100" Maximum="100" /> |
||||
|
|
||||
|
<Label Grid.Row="3" Grid.Column="2">Center Z: </Label> |
||||
|
<Slider Grid.Row="3" Grid.Column="3" Value="{Binding CenterZ}" Minimum="-100" Maximum="100" /> |
||||
|
|
||||
|
<Label Grid.Row="4" Grid.Column="2">Angle X: </Label> |
||||
|
<Slider Grid.Row="4" Grid.Column="3" Value="{Binding AngleX}" Minimum="-180" Maximum="180" /> |
||||
|
|
||||
|
<Label Grid.Row="5" Grid.Column="2">Angle Y: </Label> |
||||
|
<Slider Grid.Row="5" Grid.Column="3" Value="{Binding AngleY}" Minimum="-180" Maximum="180" /> |
||||
|
|
||||
|
<Label Grid.Row="6" Grid.Column="2">Angle Z: </Label> |
||||
|
<Slider Grid.Row="6" Grid.Column="3" Value="{Binding AngleZ}" Minimum="-180" Maximum="180" /> |
||||
|
</Grid> |
||||
|
</UserControl> |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Markup.Xaml; |
||||
|
using RenderDemo.ViewModels; |
||||
|
|
||||
|
namespace RenderDemo.Pages; |
||||
|
|
||||
|
public class Transform3DPage : UserControl |
||||
|
{ |
||||
|
public Transform3DPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
this.DataContext = new Transform3DPageViewModel(); |
||||
|
} |
||||
|
|
||||
|
private void InitializeComponent() |
||||
|
{ |
||||
|
AvaloniaXamlLoader.Load(this); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,55 @@ |
|||||
|
using System; |
||||
|
using MiniMvvm; |
||||
|
using Avalonia.Animation; |
||||
|
|
||||
|
namespace RenderDemo.ViewModels |
||||
|
{ |
||||
|
public class Transform3DPageViewModel : ViewModelBase |
||||
|
{ |
||||
|
private double _depth = 200; |
||||
|
|
||||
|
private double _centerX = 0; |
||||
|
private double _centerY = 0; |
||||
|
private double _centerZ = 0; |
||||
|
private double _angleX = 0; |
||||
|
private double _angleY = 0; |
||||
|
private double _angleZ = 0; |
||||
|
|
||||
|
public double Depth |
||||
|
{ |
||||
|
get => _depth; |
||||
|
set => RaiseAndSetIfChanged(ref _depth, value); |
||||
|
} |
||||
|
|
||||
|
public double CenterX |
||||
|
{ |
||||
|
get => _centerX; |
||||
|
set => RaiseAndSetIfChanged(ref _centerX, value); |
||||
|
} |
||||
|
public double CenterY |
||||
|
{ |
||||
|
get => _centerY; |
||||
|
set => RaiseAndSetIfChanged(ref _centerY, value); |
||||
|
} |
||||
|
public double CenterZ |
||||
|
{ |
||||
|
get => _centerZ; |
||||
|
set => RaiseAndSetIfChanged(ref _centerZ, value); |
||||
|
} |
||||
|
public double AngleX |
||||
|
{ |
||||
|
get => _angleX; |
||||
|
set => RaiseAndSetIfChanged(ref _angleX, value); |
||||
|
} |
||||
|
public double AngleY |
||||
|
{ |
||||
|
get => _angleY; |
||||
|
set => RaiseAndSetIfChanged(ref _angleY, value); |
||||
|
} |
||||
|
public double AngleZ |
||||
|
{ |
||||
|
get => _angleZ; |
||||
|
set => RaiseAndSetIfChanged(ref _angleZ, value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Styling; |
||||
|
|
||||
|
namespace Avalonia.Animation; |
||||
|
|
||||
|
public class Rotate3DTransition: PageSlide |
||||
|
{ |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new instance of the <see cref="Rotate3DTransition"/>
|
||||
|
/// </summary>
|
||||
|
/// <param name="duration">How long the rotation should take place</param>
|
||||
|
/// <param name="orientation">The orientation of the rotation</param>
|
||||
|
/// <param name="depth">Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height of the common parent of the visual being rotated</param>
|
||||
|
public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal, double? depth = null) |
||||
|
: base(duration, orientation) |
||||
|
{ |
||||
|
Depth = depth; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height
|
||||
|
/// of the common parent of the visual being rotated.
|
||||
|
/// </summary>
|
||||
|
public double? Depth { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new instance of the <see cref="Rotate3DTransition"/>
|
||||
|
/// </summary>
|
||||
|
public Rotate3DTransition() { } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override async Task Start(Visual? @from, Visual? to, bool forward, CancellationToken cancellationToken) |
||||
|
{ |
||||
|
if (cancellationToken.IsCancellationRequested) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var tasks = new Task[from != null && to != null ? 2 : 1]; |
||||
|
var parent = GetVisualParent(from, to); |
||||
|
var (rotateProperty, center) = Orientation switch |
||||
|
{ |
||||
|
SlideAxis.Vertical => (Rotate3DTransform.AngleXProperty, parent.Bounds.Height), |
||||
|
SlideAxis.Horizontal => (Rotate3DTransform.AngleYProperty, parent.Bounds.Width), |
||||
|
_ => throw new ArgumentOutOfRangeException() |
||||
|
}; |
||||
|
|
||||
|
var depthSetter = new Setter {Property = Rotate3DTransform.DepthProperty, Value = Depth ?? center}; |
||||
|
var centerZSetter = new Setter {Property = Rotate3DTransform.CenterZProperty, Value = -center / 2}; |
||||
|
|
||||
|
KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex, bool isVisible = true) => |
||||
|
new() { |
||||
|
Setters = |
||||
|
{ |
||||
|
new Setter { Property = rotateProperty, Value = rotation }, |
||||
|
new Setter { Property = Visual.ZIndexProperty, Value = zIndex }, |
||||
|
new Setter { Property = Visual.IsVisibleProperty, Value = isVisible }, |
||||
|
centerZSetter, |
||||
|
depthSetter |
||||
|
}, |
||||
|
Cue = new Cue(cue) |
||||
|
}; |
||||
|
|
||||
|
if (from != null) |
||||
|
{ |
||||
|
var animation = new Animation |
||||
|
{ |
||||
|
Easing = SlideOutEasing, |
||||
|
Duration = Duration, |
||||
|
FillMode = FillMode.Forward, |
||||
|
Children = |
||||
|
{ |
||||
|
CreateKeyFrame(0d, 0d, 2), |
||||
|
CreateKeyFrame(0.5d, 45d * (forward ? -1 : 1), 1), |
||||
|
CreateKeyFrame(1d, 90d * (forward ? -1 : 1), 1, isVisible: false) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
tasks[0] = animation.RunAsync(from, null, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
if (to != null) |
||||
|
{ |
||||
|
to.IsVisible = true; |
||||
|
var animation = new Animation |
||||
|
{ |
||||
|
Easing = SlideInEasing, |
||||
|
Duration = Duration, |
||||
|
FillMode = FillMode.Forward, |
||||
|
Children = |
||||
|
{ |
||||
|
CreateKeyFrame(0d, 90d * (forward ? 1 : -1), 1), |
||||
|
CreateKeyFrame(0.5d, 45d * (forward ? 1 : -1), 1), |
||||
|
CreateKeyFrame(1d, 0d, 2) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
tasks[from != null ? 1 : 0] = animation.RunAsync(to, null, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
await Task.WhenAll(tasks); |
||||
|
|
||||
|
if (!cancellationToken.IsCancellationRequested) |
||||
|
{ |
||||
|
if (to != null) |
||||
|
{ |
||||
|
to.ZIndex = 2; |
||||
|
} |
||||
|
|
||||
|
if (from != null) |
||||
|
{ |
||||
|
from.IsVisible = false; |
||||
|
from.ZIndex = 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,210 @@ |
|||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using Avalonia.Animation.Animators; |
||||
|
|
||||
|
namespace Avalonia.Media; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Non-Affine 3D transformation for rotating a visual around a definable axis
|
||||
|
/// </summary>
|
||||
|
public class Rotate3DTransform : Transform |
||||
|
{ |
||||
|
private readonly bool _isInitializing; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="AngleX"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> AngleXProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(AngleX)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="AngleY"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> AngleYProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(AngleY)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="AngleZ"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> AngleZProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(AngleZ)); |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="CenterX"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> CenterXProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(CenterX)); |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="CenterY"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> CenterYProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(CenterY)); |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="CenterZ"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> CenterZProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(CenterZ)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Depth"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<double> DepthProperty = |
||||
|
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(Depth)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Rotate3DTransform"/> class.
|
||||
|
/// </summary>
|
||||
|
public Rotate3DTransform() { } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Rotate3DTransform"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="angleX">The rotation around the X-Axis</param>
|
||||
|
/// <param name="angleY">The rotation around the Y-Axis</param>
|
||||
|
/// <param name="angleZ">The rotation around the Z-Axis</param>
|
||||
|
/// <param name="centerX">The origin of the X-Axis</param>
|
||||
|
/// <param name="centerY">The origin of the Y-Axis</param>
|
||||
|
/// <param name="centerZ">The origin of the Z-Axis</param>
|
||||
|
/// <param name="depth">The depth of the 3D effect</param>
|
||||
|
public Rotate3DTransform( |
||||
|
double angleX, |
||||
|
double angleY, |
||||
|
double angleZ, |
||||
|
double centerX, |
||||
|
double centerY, |
||||
|
double centerZ, |
||||
|
double depth) : this() |
||||
|
{ |
||||
|
_isInitializing = true; |
||||
|
AngleX = angleX; |
||||
|
AngleY = angleY; |
||||
|
AngleZ = angleZ; |
||||
|
CenterX = centerX; |
||||
|
CenterY = centerY; |
||||
|
CenterZ = centerZ; |
||||
|
Depth = depth; |
||||
|
_isInitializing = false; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the rotation around the X-Axis
|
||||
|
/// </summary>
|
||||
|
public double AngleX |
||||
|
{ |
||||
|
get => GetValue(AngleXProperty); |
||||
|
set => SetValue(AngleXProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the rotation around the Y-Axis
|
||||
|
/// </summary>
|
||||
|
public double AngleY |
||||
|
{ |
||||
|
get => GetValue(AngleYProperty); |
||||
|
set => SetValue(AngleYProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the rotation around the Z-Axis
|
||||
|
/// </summary>
|
||||
|
public double AngleZ |
||||
|
{ |
||||
|
get => GetValue(AngleZProperty); |
||||
|
set => SetValue(AngleZProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Moves the origin the X-Axis rotates around
|
||||
|
/// </summary>
|
||||
|
public double CenterX |
||||
|
{ |
||||
|
get => GetValue(CenterXProperty); |
||||
|
set => SetValue(CenterXProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Moves the origin the Y-Axis rotates around
|
||||
|
/// </summary>
|
||||
|
public double CenterY |
||||
|
{ |
||||
|
get => GetValue(CenterYProperty); |
||||
|
set => SetValue(CenterYProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Moves the origin the Z-Axis rotates around
|
||||
|
/// </summary>
|
||||
|
public double CenterZ |
||||
|
{ |
||||
|
get => GetValue(CenterZProperty); |
||||
|
set => SetValue(CenterZProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Affects the depth of the rotation effect
|
||||
|
/// </summary>
|
||||
|
public double Depth |
||||
|
{ |
||||
|
get => GetValue(DepthProperty); |
||||
|
set => SetValue(DepthProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the transform's <see cref="Matrix"/>.
|
||||
|
/// </summary>
|
||||
|
public override Matrix Value |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
var matrix44 = Matrix4x4.Identity; |
||||
|
//Copy values first, because it's not guaranteed, that values will not change during calculation
|
||||
|
var (copyCenterX, |
||||
|
copyCenterY, |
||||
|
copyCenterZ, |
||||
|
copyAngleX, |
||||
|
copyAngleY, |
||||
|
copyAngleZ, |
||||
|
copyDepth) = (CenterX, CenterY, CenterZ, AngleX, AngleY, AngleZ, Depth); |
||||
|
|
||||
|
var centerSum = copyCenterX + copyCenterY + copyCenterZ; |
||||
|
|
||||
|
if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation(-(float)copyCenterX, -(float)copyCenterY, -(float)copyCenterZ); |
||||
|
|
||||
|
if (copyAngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(copyAngleX)); |
||||
|
if (copyAngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(copyAngleY)); |
||||
|
if (copyAngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(copyAngleZ)); |
||||
|
|
||||
|
if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation((float)copyCenterX, (float)copyCenterY, (float)copyCenterZ); |
||||
|
|
||||
|
if (copyDepth != 0) |
||||
|
{ |
||||
|
var perspectiveMatrix = Matrix4x4.Identity; |
||||
|
perspectiveMatrix.M34 = -1 / (float)copyDepth; |
||||
|
matrix44 *= perspectiveMatrix; |
||||
|
} |
||||
|
|
||||
|
var matrix = new Matrix( |
||||
|
matrix44.M11, |
||||
|
matrix44.M12, |
||||
|
matrix44.M14, |
||||
|
matrix44.M21, |
||||
|
matrix44.M22, |
||||
|
matrix44.M24, |
||||
|
matrix44.M41, |
||||
|
matrix44.M42, |
||||
|
matrix44.M44); |
||||
|
|
||||
|
return matrix; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) |
||||
|
{ |
||||
|
if (!_isInitializing) RaiseChanged(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Styling |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The `^` nesting style selector.
|
||||
|
/// </summary>
|
||||
|
internal class NestingSelector : Selector |
||||
|
{ |
||||
|
public override bool InTemplate => false; |
||||
|
public override bool IsCombinator => false; |
||||
|
public override Type? TargetType => null; |
||||
|
|
||||
|
public override string ToString() => "^"; |
||||
|
|
||||
|
protected override SelectorMatch Evaluate(IStyleable control, IStyle? parent, bool subscribe) |
||||
|
{ |
||||
|
if (parent is Style s && s.Selector is Selector selector) |
||||
|
{ |
||||
|
return selector.Match(control, (parent as Style)?.Parent, subscribe); |
||||
|
} |
||||
|
|
||||
|
throw new InvalidOperationException( |
||||
|
"Nesting selector was specified but cannot determine parent selector."); |
||||
|
} |
||||
|
|
||||
|
protected override Selector? MovePrevious() => null; |
||||
|
internal override bool HasValidNestingSelector() => true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Avalonia.Styling |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Simple cache for improving performance of applying styles.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Maps <see cref="IStyleable.StyleKey"/> to a list of styles that are known be be possible
|
||||
|
/// matches.
|
||||
|
/// </remarks>
|
||||
|
internal class StyleCache : Dictionary<Type, List<IStyle>?> |
||||
|
{ |
||||
|
public SelectorMatchResult TryAttach(IList<IStyle> styles, IStyleable target, IStyleHost? host) |
||||
|
{ |
||||
|
if (TryGetValue(target.StyleKey, out var cached)) |
||||
|
{ |
||||
|
if (cached is object) |
||||
|
{ |
||||
|
var result = SelectorMatchResult.NeverThisType; |
||||
|
|
||||
|
foreach (var style in cached) |
||||
|
{ |
||||
|
var childResult = style.TryAttach(target, host); |
||||
|
if (childResult > result) |
||||
|
result = childResult; |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return SelectorMatchResult.NeverThisType; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
List<IStyle>? matches = null; |
||||
|
|
||||
|
foreach (var child in styles) |
||||
|
{ |
||||
|
if (child.TryAttach(target, host) != SelectorMatchResult.NeverThisType) |
||||
|
{ |
||||
|
matches ??= new List<IStyle>(); |
||||
|
matches.Add(child); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Add(target.StyleKey, matches); |
||||
|
|
||||
|
return matches is null ? |
||||
|
SelectorMatchResult.NeverThisType : |
||||
|
SelectorMatchResult.AlwaysThisType; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System.Collections.ObjectModel; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace Avalonia.Styling |
||||
|
{ |
||||
|
internal class StyleChildren : Collection<IStyle> |
||||
|
{ |
||||
|
private readonly Style _owner; |
||||
|
|
||||
|
public StyleChildren(Style owner) => _owner = owner; |
||||
|
|
||||
|
protected override void InsertItem(int index, IStyle item) |
||||
|
{ |
||||
|
(item as Style)?.SetParent(_owner); |
||||
|
base.InsertItem(index, item); |
||||
|
} |
||||
|
|
||||
|
protected override void RemoveItem(int index) |
||||
|
{ |
||||
|
var item = Items[index]; |
||||
|
(item as Style)?.SetParent(null); |
||||
|
if (_owner.Owner is IResourceHost host) |
||||
|
(item as IResourceProvider)?.RemoveOwner(host); |
||||
|
base.RemoveItem(index); |
||||
|
} |
||||
|
|
||||
|
protected override void SetItem(int index, IStyle item) |
||||
|
{ |
||||
|
(item as Style)?.SetParent(_owner); |
||||
|
base.SetItem(index, item); |
||||
|
if (_owner.Owner is IResourceHost host) |
||||
|
(item as IResourceProvider)?.AddOwner(host); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,294 +1,321 @@ |
|||||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
<Style xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
Selector="CheckBox"> |
||||
<Design.PreviewWith> |
<Design.PreviewWith> |
||||
<Border Padding="20"> |
<Border Padding="20"> |
||||
<CheckBox IsThreeState="True" IsChecked="True" Content="Content" Foreground="Gold" /> |
<CheckBox IsThreeState="True" IsChecked="True" Content="Content" Foreground="Gold" /> |
||||
</Border> |
</Border> |
||||
</Design.PreviewWith> |
</Design.PreviewWith> |
||||
<Style Selector="CheckBox"> |
|
||||
<Setter Property="Padding" Value="8,0,0,0" /> |
<Setter Property="Padding" Value="8,0,0,0" /> |
||||
<Setter Property="HorizontalAlignment" Value="Left" /> |
<Setter Property="HorizontalAlignment" Value="Left" /> |
||||
<Setter Property="VerticalAlignment" Value="Center" /> |
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
<Setter Property="HorizontalContentAlignment" Value="Left" /> |
<Setter Property="HorizontalContentAlignment" Value="Left" /> |
||||
<Setter Property="VerticalContentAlignment" Value="Center" /> |
<Setter Property="VerticalContentAlignment" Value="Center" /> |
||||
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" /> |
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" /> |
||||
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" /> |
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" /> |
||||
<Setter Property="MinHeight" Value="32" /> |
<Setter Property="MinHeight" Value="32" /> |
||||
<!--<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" /> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" /> |
||||
<Setter Property="FocusVisualMargin" Value="-7,-3,-7,-3" />--> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUnchecked}" /> |
||||
<Setter Property="Template"> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUnchecked}" /> |
||||
<ControlTemplate> |
<Setter Property="Template"> |
||||
<Grid x:Name="RootGrid" ColumnDefinitions="20,*"> |
<ControlTemplate> |
||||
<Border x:Name="PART_Border" |
<Grid x:Name="RootGrid" ColumnDefinitions="20,*"> |
||||
Grid.ColumnSpan="2" |
<Border x:Name="PART_Border" |
||||
Background="{TemplateBinding Background}" |
Grid.ColumnSpan="2" |
||||
BorderBrush="{TemplateBinding BorderBrush}" |
Background="{TemplateBinding Background}" |
||||
BorderThickness="{TemplateBinding BorderThickness}" |
BorderBrush="{TemplateBinding BorderBrush}" |
||||
CornerRadius="{TemplateBinding CornerRadius}" /> |
BorderThickness="{TemplateBinding BorderThickness}" |
||||
|
CornerRadius="{TemplateBinding CornerRadius}" /> |
||||
<Grid VerticalAlignment="Top" Height="32"> |
|
||||
<Border x:Name="NormalRectangle" |
<Grid VerticalAlignment="Top" Height="32"> |
||||
BorderThickness="{DynamicResource CheckBoxBorderThemeThickness}" |
<Border x:Name="NormalRectangle" |
||||
CornerRadius="{TemplateBinding CornerRadius}" |
BorderThickness="{DynamicResource CheckBoxBorderThemeThickness}" |
||||
UseLayoutRounding="False" |
CornerRadius="{TemplateBinding CornerRadius}" |
||||
Height="20" |
UseLayoutRounding="False" |
||||
Width="20" /> |
Height="20" |
||||
|
Width="20" /> |
||||
<Viewbox UseLayoutRounding="False"> |
|
||||
<Panel> |
<Viewbox UseLayoutRounding="False"> |
||||
<Panel Height="16" Width="16" /> |
<Panel> |
||||
<Path x:Name="CheckGlyph" Stretch="Uniform" VerticalAlignment="Center" /> |
<Panel Height="16" Width="16" /> |
||||
</Panel> |
<Path x:Name="CheckGlyph" Stretch="Uniform" VerticalAlignment="Center" /> |
||||
</Viewbox> |
</Panel> |
||||
</Grid> |
</Viewbox> |
||||
<ContentPresenter x:Name="ContentPresenter" |
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}" |
|
||||
Content="{TemplateBinding Content}" |
|
||||
Margin="{TemplateBinding Padding}" |
|
||||
RecognizesAccessKey="True" |
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" |
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" |
|
||||
Grid.Column="1" /> |
|
||||
<!-- TODO: TextWrapping="Wrap" on contentpresenter --> |
|
||||
</Grid> |
</Grid> |
||||
</ControlTemplate> |
<ContentPresenter x:Name="ContentPresenter" |
||||
</Setter> |
ContentTemplate="{TemplateBinding ContentTemplate}" |
||||
</Style> |
Content="{TemplateBinding Content}" |
||||
|
Margin="{TemplateBinding Padding}" |
||||
<!-- Unchecked Normal State --> |
RecognizesAccessKey="True" |
||||
<Style Selector="CheckBox"> |
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" /> |
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" |
||||
</Style> |
Grid.Column="1" /> |
||||
|
<!-- TODO: TextWrapping="Wrap" on contentpresenter --> |
||||
<Style Selector="CheckBox"> |
</Grid> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUnchecked}" /> |
</ControlTemplate> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUnchecked}" /> |
</Setter> |
||||
</Style> |
|
||||
|
<Style.Children> |
||||
<Style Selector="CheckBox /template/ Border#NormalRectangle"> |
<!-- Unchecked Normal State --> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUnchecked}" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUnchecked}" /> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUnchecked}" /> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUnchecked}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox /template/ Path#CheckGlyph"> |
|
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUnchecked}" /> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
<Setter Property="Opacity" Value="0" /> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUnchecked}" /> |
||||
</Style> |
<Setter Property="Opacity" Value="0" /> |
||||
|
</Style> |
||||
<!-- Unchecked PointerOver State --> |
|
||||
<Style Selector="CheckBox:pointerover /template/ ContentPresenter#ContentPresenter"> |
<!-- Unchecked PointerOver State --> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPointerOver}" /> |
<Style Selector="^:pointerover"> |
||||
</Style> |
<Style.Children> |
||||
|
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
<Style Selector="CheckBox:pointerover /template/ Border#PART_Border"> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPointerOver}" /> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPointerOver}" /> |
</Style> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPointerOver}" /> |
|
||||
</Style> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
|
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPointerOver}" /> |
||||
<Style Selector="CheckBox:pointerover /template/ Border#NormalRectangle"> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPointerOver}" /> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPointerOver}" /> |
</Style> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPointerOver}" /> |
|
||||
</Style> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPointerOver}" /> |
||||
<Style Selector="CheckBox:pointerover /template/ Path#CheckGlyph"> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPointerOver}" /> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPointerOver}" /> |
</Style> |
||||
</Style> |
|
||||
|
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
<!-- Unchecked Pressed State --> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPointerOver}" /> |
||||
<Style Selector="CheckBox:pressed /template/ ContentPresenter#ContentPresenter"> |
</Style> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPressed}" /> |
</Style.Children> |
||||
</Style> |
</Style> |
||||
|
|
||||
<Style Selector="CheckBox:pressed /template/ Border#PART_Border"> |
<!-- Unchecked Pressed State --> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPressed}" /> |
<Style Selector="^:pressed"> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPressed}" /> |
<Style.Children> |
||||
</Style> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPressed}" /> |
||||
<Style Selector="CheckBox:pressed /template/ Border#NormalRectangle"> |
</Style> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPressed}" /> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPressed}" /> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPressed}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPressed}" /> |
||||
<Style Selector="CheckBox:pressed /template/ Path#CheckGlyph"> |
</Style> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPressed}" /> |
|
||||
</Style> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPressed}" /> |
||||
<!-- Unchecked Disabled state --> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPressed}" /> |
||||
<Style Selector="CheckBox:disabled /template/ ContentPresenter#ContentPresenter"> |
</Style> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedDisabled}" /> |
|
||||
</Style> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
|
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPressed}" /> |
||||
<Style Selector="CheckBox:disabled /template/ Border#PART_Border"> |
</Style> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedDisabled}" /> |
</Style.Children> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedDisabled}" /> |
</Style> |
||||
</Style> |
|
||||
|
<!-- Unchecked Disabled state --> |
||||
<Style Selector="CheckBox:disabled /template/ Border#NormalRectangle"> |
<Style Selector="^:disabled"> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedDisabled}" /> |
<Style.Children> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedDisabled}" /> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
</Style> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedDisabled}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:disabled /template/ Path#CheckGlyph"> |
|
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedDisabled}" /> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedDisabled}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedDisabled}" /> |
||||
|
</Style> |
||||
<!-- Checked Normal State --> |
|
||||
<Style Selector="CheckBox:checked"> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" /> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedDisabled}" /> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedDisabled}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:checked"> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundChecked}" /> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushChecked}" /> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedDisabled}" /> |
||||
</Style> |
</Style> |
||||
|
</Style.Children> |
||||
<Style Selector="CheckBox:checked /template/ Border#NormalRectangle"> |
</Style> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" /> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" /> |
<Style Selector="^:checked"> |
||||
</Style> |
<!-- Checked Normal State --> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" /> |
||||
<Style Selector="CheckBox:checked /template/ Path#CheckGlyph"> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundChecked}" /> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundChecked}" /> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushChecked}" /> |
||||
<Setter Property="Data" Value="M1507 31L438 1101L-119 543L-29 453L438 919L1417 -59L1507 31Z" /> |
|
||||
<Setter Property="Width" Value="9" /> |
<Style.Children> |
||||
<Setter Property="Opacity" Value="1" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
<Setter Property="FlowDirection" Value="LeftToRight" /> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" /> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" /> |
||||
|
</Style> |
||||
<!-- Checked PointerOver State --> |
|
||||
<Style Selector="CheckBox:checked:pointerover /template/ ContentPresenter#ContentPresenter"> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPointerOver}" /> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundChecked}" /> |
||||
</Style> |
<Setter Property="Data" Value="M1507 31L438 1101L-119 543L-29 453L438 919L1417 -59L1507 31Z" /> |
||||
|
<Setter Property="Width" Value="9" /> |
||||
<Style Selector="CheckBox:checked:pointerover /template/ Border#PART_Border"> |
<Setter Property="Opacity" Value="1" /> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPointerOver}" /> |
<Setter Property="FlowDirection" Value="LeftToRight" /> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPointerOver}" /> |
</Style> |
||||
</Style> |
|
||||
|
<!-- Checked PointerOver State --> |
||||
<Style Selector="CheckBox:checked:pointerover /template/ Border#NormalRectangle"> |
<Style Selector="^:pointerover"> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPointerOver}" /> |
<Style.Children> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPointerOver}" /> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
</Style> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPointerOver}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:checked:pointerover /template/ Path#CheckGlyph"> |
|
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPointerOver}" /> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPointerOver}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPointerOver}" /> |
||||
<!-- Checked Pressed State --> |
</Style> |
||||
<Style Selector="CheckBox:checked:pressed /template/ ContentPresenter#ContentPresenter"> |
|
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPressed}" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
</Style> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPointerOver}" /> |
||||
|
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPointerOver}" /> |
||||
<Style Selector="CheckBox:checked:pressed /template/ Border#PART_Border"> |
</Style> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPressed}" /> |
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPressed}" /> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
</Style> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPointerOver}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:checked:pressed /template/ Border#NormalRectangle"> |
</Style.Children> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPressed}" /> |
</Style> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPressed}" /> |
|
||||
</Style> |
<!-- Checked Pressed State --> |
||||
|
<Style Selector="^:pressed"> |
||||
<Style Selector="CheckBox:checked:pressed /template/ Path#CheckGlyph"> |
<Style.Children> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPressed}" /> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
</Style> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPressed}" /> |
||||
|
</Style> |
||||
<!-- Checked Disabled State --> |
|
||||
<Style Selector="CheckBox:checked:disabled /template/ ContentPresenter#ContentPresenter"> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedDisabled}" /> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPressed}" /> |
||||
</Style> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPressed}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:checked:disabled /template/ Border#PART_Border"> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedDisabled}" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedDisabled}" /> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPressed}" /> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPressed}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:checked:disabled /template/ Border#NormalRectangle"> |
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedDisabled}" /> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedDisabled}" /> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPressed}" /> |
||||
</Style> |
</Style> |
||||
|
</Style.Children> |
||||
<Style Selector="CheckBox:checked:disabled /template/ Path#CheckGlyph"> |
</Style> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedDisabled}" /> |
|
||||
</Style> |
<!-- Checked Disabled State --> |
||||
|
<Style Selector="^:disabled"> |
||||
|
<Style.Children> |
||||
<!-- Indeterminate Normal State --> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
<Style Selector="CheckBox:indeterminate"> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedDisabled}" /> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" /> |
</Style> |
||||
</Style> |
|
||||
|
<Style Selector="^ /template/ Border#PART_Border"> |
||||
<Style Selector="CheckBox:indeterminate"> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedDisabled}" /> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminate}" /> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedDisabled}" /> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminate}" /> |
</Style> |
||||
</Style> |
|
||||
|
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
<Style Selector="CheckBox:indeterminate /template/ Border#NormalRectangle"> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedDisabled}" /> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminate}" /> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedDisabled}" /> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminate}" /> |
</Style> |
||||
</Style> |
|
||||
|
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
<Style Selector="CheckBox:indeterminate /template/ Path#CheckGlyph"> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedDisabled}" /> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminate}" /> |
</Style> |
||||
<Setter Property="Data" Value="M1536 1536v-1024h-1024v1024h1024z" /> |
</Style.Children> |
||||
<Setter Property="Width" Value="7" /> |
</Style> |
||||
<Setter Property="Opacity" Value="1" /> |
</Style.Children> |
||||
</Style> |
</Style> |
||||
|
|
||||
<!-- Indeterminate PointerOver State --> |
<Style Selector="^:indeterminate"> |
||||
<Style Selector="CheckBox:indeterminate:pointerover /template/ ContentPresenter#ContentPresenter"> |
<!-- Indeterminate Normal State --> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePointerOver}" /> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" /> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminate}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminate}" /> |
||||
<Style Selector="CheckBox:indeterminate:pointerover /template/ Border#PART_Border"> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePointerOver}" /> |
<Style.Children> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePointerOver}" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
</Style> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminate}" /> |
||||
|
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminate}" /> |
||||
<Style Selector="CheckBox:indeterminate:pointerover /template/ Border#NormalRectangle"> |
</Style> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePointerOver}" /> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePointerOver}" /> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
</Style> |
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminate}" /> |
||||
|
<Setter Property="Data" Value="M1536 1536v-1024h-1024v1024h1024z" /> |
||||
<Style Selector="CheckBox:indeterminate:pointerover /template/ Path#CheckGlyph"> |
<Setter Property="Width" Value="7" /> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePointerOver}" /> |
<Setter Property="Opacity" Value="1" /> |
||||
</Style> |
</Style> |
||||
|
|
||||
<!-- Indeterminate Pressed State --> |
<!-- Indeterminate PointerOver State --> |
||||
<Style Selector="CheckBox:indeterminate:pressed /template/ ContentPresenter#ContentPresenter"> |
<Style Selector="^:pointerover"> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePressed}" /> |
<Style.Children> |
||||
</Style> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePointerOver}" /> |
||||
<Style Selector="CheckBox:indeterminate:pressed /template/ Border#PART_Border"> |
</Style> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePressed}" /> |
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePressed}" /> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
</Style> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePointerOver}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePointerOver}" /> |
||||
<Style Selector="CheckBox:indeterminate:pressed /template/ Border#NormalRectangle"> |
</Style> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePressed}" /> |
|
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePressed}" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
</Style> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePointerOver}" /> |
||||
|
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePointerOver}" /> |
||||
<Style Selector="CheckBox:indeterminate:pressed /template/ Path#CheckGlyph"> |
</Style> |
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePressed}" /> |
|
||||
</Style> |
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
|
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePointerOver}" /> |
||||
<!-- Indeterminate Disabled State --> |
</Style> |
||||
<Style Selector="CheckBox:indeterminate:disabled /template/ ContentPresenter#ContentPresenter"> |
</Style.Children> |
||||
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminateDisabled}" /> |
</Style> |
||||
</Style> |
|
||||
|
<!-- Indeterminate Pressed State --> |
||||
<Style Selector="CheckBox:indeterminate:disabled /template/ Border#PART_Border"> |
<Style Selector="^:pressed"> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminateDisabled}" /> |
<Style.Children> |
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminateDisabled}" /> |
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
</Style> |
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePressed}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:indeterminate:disabled /template/ Border#NormalRectangle"> |
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminateDisabled}" /> |
<Style Selector="^ /template/ Border#PART_Border"> |
||||
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminateDisabled}" /> |
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePressed}" /> |
||||
</Style> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePressed}" /> |
||||
|
</Style> |
||||
<Style Selector="CheckBox:indeterminate:disabled /template/ Path#CheckGlyph"> |
|
||||
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminateDisabled}" /> |
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
</Style> |
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePressed}" /> |
||||
</Styles> |
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePressed}" /> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
|
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePressed}" /> |
||||
|
</Style> |
||||
|
</Style.Children> |
||||
|
</Style> |
||||
|
|
||||
|
<!-- Indeterminate Disabled State --> |
||||
|
<Style Selector="^:disabled"> |
||||
|
<Style.Children> |
||||
|
<Style Selector="^ /template/ ContentPresenter#ContentPresenter"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminateDisabled}" /> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="^ /template/ Border#PART_Border"> |
||||
|
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminateDisabled}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminateDisabled}" /> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="^ /template/ Border#NormalRectangle"> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminateDisabled}" /> |
||||
|
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminateDisabled}" /> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="^ /template/ Path#CheckGlyph"> |
||||
|
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminateDisabled}" /> |
||||
|
</Style> |
||||
|
</Style.Children> |
||||
|
</Style> |
||||
|
</Style.Children> |
||||
|
</Style> |
||||
|
</Style.Children> |
||||
|
</Style> |
||||
|
|||||
@ -0,0 +1,92 @@ |
|||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Media; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Visuals.UnitTests; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// These tests use the "official" Matrix4x4 and Matrix3x2 from the System.Numerics namespace, to validate
|
||||
|
/// that Avalonias own implementation of a 3x3 Matrix works correctly.
|
||||
|
/// </summary>
|
||||
|
public class MatrixTests |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Because Avalonia is working internally with doubles, but System.Numerics Vector and Matrix implementations
|
||||
|
/// only make use of floats, we need to reduce precision, comparing them. It should be sufficient to compare
|
||||
|
/// 5 fractional digits to ensure, that the result is correct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="expected">The expected vector</param>
|
||||
|
/// <param name="actual">The actual transformed point</param>
|
||||
|
private void AssertCoordinatesEqualWithReducedPrecision(Vector2 expected, Point actual) |
||||
|
{ |
||||
|
double ReducePrecision(double input) => Math.Truncate(input * 10000); |
||||
|
|
||||
|
var expectedX = ReducePrecision(expected.X); |
||||
|
var expectedY = ReducePrecision(expected.Y); |
||||
|
|
||||
|
var actualX = ReducePrecision(actual.X); |
||||
|
var actualY = ReducePrecision(actual.Y); |
||||
|
|
||||
|
Assert.Equal(expectedX, actualX); |
||||
|
Assert.Equal(expectedY, actualY); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Transform_Point_Should_Return_Correct_Value_For_Translated_Matrix() |
||||
|
{ |
||||
|
var vector2 = Vector2.Transform( |
||||
|
new Vector2(1, 1), |
||||
|
Matrix3x2.CreateTranslation(2, 2)); |
||||
|
var expected = new Point(vector2.X, vector2.Y); |
||||
|
|
||||
|
var matrix = Matrix.CreateTranslation(2, 2); |
||||
|
var point = new Point(1, 1); |
||||
|
var transformedPoint = matrix.Transform(point); |
||||
|
|
||||
|
Assert.Equal(expected, transformedPoint); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Transform_Point_Should_Return_Correct_Value_For_Rotated_Matrix() |
||||
|
{ |
||||
|
var expected = Vector2.Transform( |
||||
|
new Vector2(0, 10), |
||||
|
Matrix3x2.CreateRotation((float)Matrix.ToRadians(45))); |
||||
|
|
||||
|
var matrix = Matrix.CreateRotation(Matrix.ToRadians(45)); |
||||
|
var point = new Point(0, 10); |
||||
|
var actual = matrix.Transform(point); |
||||
|
|
||||
|
AssertCoordinatesEqualWithReducedPrecision(expected, actual); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Transform_Point_Should_Return_Correct_Value_For_Scaled_Matrix() |
||||
|
{ |
||||
|
var vector2 = Vector2.Transform( |
||||
|
new Vector2(1, 1), |
||||
|
Matrix3x2.CreateScale(2, 2)); |
||||
|
var expected = new Point(vector2.X, vector2.Y); |
||||
|
var matrix = Matrix.CreateScale(2, 2); |
||||
|
var point = new Point(1, 1); |
||||
|
var actual = matrix.Transform(point); |
||||
|
|
||||
|
Assert.Equal(expected, actual); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Transform_Point_Should_Return_Correct_Value_For_Skewed_Matrix() |
||||
|
{ |
||||
|
var expected = Vector2.Transform( |
||||
|
new Vector2(1, 1), |
||||
|
Matrix3x2.CreateSkew(30, 20)); |
||||
|
|
||||
|
var matrix = Matrix.CreateSkew(30, 20); |
||||
|
var point = new Point(1, 1); |
||||
|
var actual = matrix.Transform(point); |
||||
|
|
||||
|
AssertCoordinatesEqualWithReducedPrecision(expected, actual); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,275 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Styling; |
||||
|
using Avalonia.Styling.Activators; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Base.UnitTests.Styling |
||||
|
{ |
||||
|
public class SelectorTests_Nesting |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Nesting_Class_Doesnt_Match_Parent_OfType_Selector() |
||||
|
{ |
||||
|
var control = new Control2(); |
||||
|
Style nested; |
||||
|
var parent = new Style(x => x.OfType<Control1>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => x.Nesting().Class("foo"))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Or_Nesting_Class_Doesnt_Match_Parent_OfType_Selector() |
||||
|
{ |
||||
|
var control = new Control2(); |
||||
|
Style nested; |
||||
|
var parent = new Style(x => x.OfType<Control1>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => Selectors.Or( |
||||
|
x.Nesting().Class("foo"), |
||||
|
x.Nesting().Class("bar")))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Or_Nesting_Child_OfType_Doesnt_Match_Parent_OfType_Selector() |
||||
|
{ |
||||
|
var control = new Control1(); |
||||
|
var panel = new DockPanel { Children = { control } }; |
||||
|
Style nested; |
||||
|
var parent = new Style(x => x.OfType<Panel>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => Selectors.Or( |
||||
|
x.Nesting().Child().OfType<Control1>(), |
||||
|
x.Nesting().Child().OfType<Control1>()))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.NeverThisInstance, match.Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Double_Nesting_Class_Doesnt_Match_Grandparent_OfType_Selector() |
||||
|
{ |
||||
|
var control = new Control2 |
||||
|
{ |
||||
|
Classes = { "foo", "bar" }, |
||||
|
}; |
||||
|
|
||||
|
Style parent; |
||||
|
Style nested; |
||||
|
var grandparent = new Style(x => x.OfType<Control1>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(parent = new Style(x => x.Nesting().Class("foo")) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => x.Nesting().Class("bar"))) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Nesting_Class_Matches() |
||||
|
{ |
||||
|
var control = new Control1 { Classes = { "foo" } }; |
||||
|
Style nested; |
||||
|
var parent = new Style(x => x.OfType<Control1>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => x.Nesting().Class("foo"))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
||||
|
|
||||
|
var sink = new ActivatorSink(match.Activator); |
||||
|
|
||||
|
Assert.True(sink.Active); |
||||
|
control.Classes.Clear(); |
||||
|
Assert.False(sink.Active); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Double_Nesting_Class_Matches() |
||||
|
{ |
||||
|
var control = new Control1 |
||||
|
{ |
||||
|
Classes = { "foo", "bar" }, |
||||
|
}; |
||||
|
|
||||
|
Style parent; |
||||
|
Style nested; |
||||
|
var grandparent = new Style(x => x.OfType<Control1>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(parent = new Style(x => x.Nesting().Class("foo")) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => x.Nesting().Class("bar"))) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
||||
|
|
||||
|
var sink = new ActivatorSink(match.Activator); |
||||
|
|
||||
|
Assert.True(sink.Active); |
||||
|
control.Classes.Remove("foo"); |
||||
|
Assert.False(sink.Active); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Or_Nesting_Class_Matches() |
||||
|
{ |
||||
|
var control = new Control1 { Classes = { "foo" } }; |
||||
|
Style nested; |
||||
|
var parent = new Style(x => x.OfType<Control1>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => Selectors.Or( |
||||
|
x.Nesting().Class("foo"), |
||||
|
x.Nesting().Class("bar")))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
||||
|
|
||||
|
var sink = new ActivatorSink(match.Activator); |
||||
|
|
||||
|
Assert.True(sink.Active); |
||||
|
control.Classes.Clear(); |
||||
|
Assert.False(sink.Active); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Or_Nesting_Child_OfType_Matches() |
||||
|
{ |
||||
|
var control = new Control1 { Classes = { "foo" } }; |
||||
|
var panel = new Panel { Children = { control } }; |
||||
|
Style nested; |
||||
|
var parent = new Style(x => x.OfType<Panel>()) |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => Selectors.Or( |
||||
|
x.Nesting().Child().OfType<Control1>(), |
||||
|
x.Nesting().Child().OfType<Control1>()))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var match = nested.Selector.Match(control, parent); |
||||
|
Assert.Equal(SelectorMatchResult.AlwaysThisInstance, match.Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Nesting_With_No_Parent_Style_Fails() |
||||
|
{ |
||||
|
var control = new Control1(); |
||||
|
var style = new Style(x => x.Nesting().OfType<Control1>()); |
||||
|
|
||||
|
Assert.Throws<InvalidOperationException>(() => style.Selector.Match(control, null)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Nesting_With_No_Parent_Selector_Fails() |
||||
|
{ |
||||
|
var control = new Control1(); |
||||
|
Style nested; |
||||
|
var parent = new Style |
||||
|
{ |
||||
|
Children = |
||||
|
{ |
||||
|
(nested = new Style(x => x.Nesting().Class("foo"))), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
Assert.Throws<InvalidOperationException>(() => nested.Selector.Match(control, parent)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Adding_Child_With_No_Nesting_Selector_Fails() |
||||
|
{ |
||||
|
var parent = new Style(x => x.OfType<Control1>()); |
||||
|
var child = new Style(x => x.Class("foo")); |
||||
|
|
||||
|
Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Adding_Combinator_Selector_Child_With_No_Nesting_Selector_Fails() |
||||
|
{ |
||||
|
var parent = new Style(x => x.OfType<Control1>()); |
||||
|
var child = new Style(x => x.Class("foo").Descendant().Class("bar")); |
||||
|
|
||||
|
Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Adding_Or_Selector_Child_With_No_Nesting_Selector_Fails() |
||||
|
{ |
||||
|
var parent = new Style(x => x.OfType<Control1>()); |
||||
|
var child = new Style(x => Selectors.Or( |
||||
|
x.Nesting().Class("foo"), |
||||
|
x.Class("bar"))); |
||||
|
|
||||
|
Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Can_Add_Child_Without_Nesting_Selector_To_Style_Without_Selector() |
||||
|
{ |
||||
|
var parent = new Style(); |
||||
|
var child = new Style(x => x.Class("foo")); |
||||
|
|
||||
|
parent.Children.Add(child); |
||||
|
} |
||||
|
|
||||
|
public class Control1 : Control |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public class Control2 : Control |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
private class ActivatorSink : IStyleActivatorSink |
||||
|
{ |
||||
|
public ActivatorSink(IStyleActivator source) => source.Subscribe(this); |
||||
|
public bool Active { get; private set; } |
||||
|
public void OnNext(bool value, int tag) => Active = value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue