Skip to content

Commit

Permalink
Merge branch 'LayoutTransform' of https://github.com/donandren/Perspex
Browse files Browse the repository at this point in the history
…into donandren-LayoutTransform
  • Loading branch information
grokys committed Mar 17, 2016
2 parents c4f7de1 + a530f5b commit ba4b3b0
Show file tree
Hide file tree
Showing 10 changed files with 730 additions and 0 deletions.
389 changes: 389 additions & 0 deletions src/Perspex.Controls/LayoutTransformControl.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Perspex.Controls/Perspex.Controls.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
<Compile Include="INameScope.cs" />
<Compile Include="IPseudoClasses.cs" />
<Compile Include="DropDownItem.cs" />
<Compile Include="LayoutTransformControl.cs" />
<Compile Include="Mixins\ContentControlMixin.cs" />
<Compile Include="NameScope.cs" />
<Compile Include="NameScopeEventArgs.cs" />
Expand Down
6 changes: 6 additions & 0 deletions src/Perspex.SceneGraph/Matrix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public Matrix(
/// </summary>
public bool IsIdentity => Equals(Identity);

/// <summary>
/// HasInverse Property - returns true if this matrix is invertable, false otherwise.
/// </summary>
public bool HasInverse => GetDeterminant() != 0;

/// <summary>
/// The first element of the first row
/// </summary>
Expand Down Expand Up @@ -209,6 +214,7 @@ public double GetDeterminant()
return (_m11 * _m22) - (_m12 * _m21);
}


/// <summary>
/// Returns a boolean indicating whether the matrix is equal to the other given matrix.
/// </summary>
Expand Down
69 changes: 69 additions & 0 deletions src/Perspex.SceneGraph/Media/ScaleTransform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.

using System;

namespace Perspex.Media
{
/// <summary>
/// Scale an <see cref="IVisual"/>.
/// </summary>
public class ScaleTransform : Transform
{
/// <summary>
/// Defines the <see cref="ScaleX"/> property.
/// </summary>
public static readonly StyledProperty<double> ScaleXProperty =
PerspexProperty.Register<ScaleTransform, double>(nameof(ScaleX), 1);

/// <summary>
/// Defines the <see cref="ScaleY"/> property.
/// </summary>
public static readonly StyledProperty<double> ScaleYProperty =
PerspexProperty.Register<ScaleTransform, double>(nameof(ScaleY), 1);

/// <summary>
/// Initializes a new instance of the <see cref="ScaleTransform"/> class.
/// </summary>
public ScaleTransform()
{
this.GetObservable(ScaleXProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(ScaleYProperty).Subscribe(_ => RaiseChanged());
}

/// <summary>
/// Initializes a new instance of the <see cref="ScaleTransform"/> class.
/// </summary>
/// <param name="scaleX">ScaleX</param>
/// <param name="scaleY">ScaleY</param>
public ScaleTransform(double scaleX, double scaleY)
: this()
{
ScaleX = scaleX;
ScaleY = scaleY;
}

/// <summary>
/// Gets or sets the ScaleX property.
/// </summary>
public double ScaleX
{
get { return GetValue(ScaleXProperty); }
set { SetValue(ScaleXProperty, value); }
}

/// <summary>
/// Gets or sets the ScaleY property.
/// </summary>
public double ScaleY
{
get { return GetValue(ScaleYProperty); }
set { SetValue(ScaleYProperty, value); }
}

/// <summary>
/// Gets the tranform's <see cref="Matrix"/>.
/// </summary>
public override Matrix Value => Matrix.CreateScale(ScaleX, ScaleY);
}
}
1 change: 1 addition & 0 deletions src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Compile Include="Media\LinearGradientBrush.cs" />
<Compile Include="Media\MediaExtensions.cs" />
<Compile Include="Media\PenLineCap.cs" />
<Compile Include="Media\ScaleTransform.cs" />
<Compile Include="Media\TextAlignment.cs" />
<Compile Include="Media\FontWeight.cs" />
<Compile Include="Media\FontStyle.cs" />
Expand Down
1 change: 1 addition & 0 deletions src/Perspex.Themes.Default/DefaultTheme.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<StyleInclude Source="resm:Perspex.Themes.Default.DropDownItem.xaml?assembly=Perspex.Themes.Default"/>
<StyleInclude Source="resm:Perspex.Themes.Default.GridSplitter.xaml?assembly=Perspex.Themes.Default"/>
<StyleInclude Source="resm:Perspex.Themes.Default.ItemsControl.xaml?assembly=Perspex.Themes.Default"/>
<StyleInclude Source="resm:Perspex.Themes.Default.LayoutTransformControl.xaml?assembly=Perspex.Themes.Default"/>
<StyleInclude Source="resm:Perspex.Themes.Default.ListBox.xaml?assembly=Perspex.Themes.Default"/>
<StyleInclude Source="resm:Perspex.Themes.Default.ListBoxItem.xaml?assembly=Perspex.Themes.Default"/>
<StyleInclude Source="resm:Perspex.Themes.Default.Menu.xaml?assembly=Perspex.Themes.Default"/>
Expand Down
12 changes: 12 additions & 0 deletions src/Perspex.Themes.Default/LayoutTransformControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Style xmlns="https://github.com/perspex" Selector="LayoutTransformControl">
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>
5 changes: 5 additions & 0 deletions src/Perspex.Themes.Default/Perspex.Themes.Default.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="LayoutTransformControl.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
245 changes: 245 additions & 0 deletions tests/Perspex.Controls.UnitTests/LayoutTransformControlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
using Perspex.Controls.Presenters;
using Perspex.Controls.Shapes;
using Perspex.Controls.Templates;
using Perspex.Media;
using Xunit;

namespace Perspex.Controls.UnitTests
{
public class LayoutTransformControlTests
{
[Fact]
public void Measure_On_Scale_x2_Is_Correct()
{
double scale = 2;

TransformMeasureSizeTest(
new Size(100, 50),
new ScaleTransform() { ScaleX = scale, ScaleY = scale },
new Size(200, 100));
}

[Fact]
public void Measure_On_Scale_x0_5_Is_Correct()
{
double scale = 0.5;

TransformMeasureSizeTest(
new Size(100, 50),
new ScaleTransform() { ScaleX = scale, ScaleY = scale },
new Size(50, 25));
}

[Fact]
public void Measure_On_Rotate_90_degrees_Is_Correct()
{
TransformMeasureSizeTest(
new Size(100, 25),
new RotateTransform() { Angle = 90 },
new Size(25, 100));
}

[Fact]
public void Measure_On_Rotate_minus_90_degrees_Is_Correct()
{
TransformMeasureSizeTest(
new Size(100, 25),
new RotateTransform() { Angle = -90 },
new Size(25, 100));
}

[Fact]
public void Measure_On_Rotate_0_degrees_Is_Correct()
{
TransformMeasureSizeTest(
new Size(100, 25),
new RotateTransform() { Angle = 0 },
new Size(100, 25));
}

[Fact]
public void Measure_On_Rotate_180_degrees_Is_Correct()
{
TransformMeasureSizeTest(
new Size(100, 25),
new RotateTransform() { Angle = 180 },
new Size(100, 25));
}

[Fact]
public void Bounds_On_Scale_x2_Are_correct()
{
double scale = 2;

TransformRootBoundsTest(
new Size(100, 50),
new ScaleTransform() { ScaleX = scale, ScaleY = scale },
new Rect(0, 0, 100, 50));
}

[Fact]
public void Bounds_On_Scale_x0_5_Are_correct()
{
double scale = 0.5;

TransformRootBoundsTest(
new Size(100, 50),
new ScaleTransform() { ScaleX = scale, ScaleY = scale },
new Rect(0, 0, 100, 50));
}

[Fact]
public void Bounds_On_Rotate_180_degrees_Are_correct()
{
TransformRootBoundsTest(
new Size(100, 25),
new RotateTransform() { Angle = 180 },
new Rect(100, 25, 100, 25));
}

[Fact]
public void Bounds_On_Rotate_0_degrees_Are_correct()
{
TransformRootBoundsTest(
new Size(100, 25),
new RotateTransform() { Angle = 0 },
new Rect(0, 0, 100, 25));
}

[Fact]
public void Bounds_On_Rotate_90_degrees_Are_correct()
{
TransformRootBoundsTest(
new Size(100, 25),
new RotateTransform() { Angle = 90 },
new Rect(25, 0, 100, 25));
}

[Fact]
public void Bounds_On_Rotate_minus_90_degrees_Are_correct()
{
TransformRootBoundsTest(
new Size(100, 25),
new RotateTransform() { Angle = -90 },
new Rect(0, 100, 100, 25));
}

[Fact]
public void Should_Generate_RenderTransform_90_degrees()
{
LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(
100,
25,
new RotateTransform() { Angle = 90 });

Assert.NotNull(lt.TransformRoot.RenderTransform);

Matrix m = lt.TransformRoot.RenderTransform.Value;

Matrix res = Matrix.CreateRotation(Matrix.ToRadians(90));

Assert.Equal(m.M11, res.M11, 3);
Assert.Equal(m.M12, res.M12, 3);
Assert.Equal(m.M21, res.M21, 3);
Assert.Equal(m.M22, res.M22, 3);
Assert.Equal(m.M31, res.M31, 3);
Assert.Equal(m.M32, res.M32, 3);
}

[Fact]
public void Should_Generate_RenderTransform_minus_90_degrees()
{
LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(
100,
25,
new RotateTransform() { Angle = -90 });

Assert.NotNull(lt.TransformRoot.RenderTransform);

var m = lt.TransformRoot.RenderTransform.Value;

var res = Matrix.CreateRotation(Matrix.ToRadians(-90));

Assert.Equal(m.M11, res.M11, 3);
Assert.Equal(m.M12, res.M12, 3);
Assert.Equal(m.M21, res.M21, 3);
Assert.Equal(m.M22, res.M22, 3);
Assert.Equal(m.M31, res.M31, 3);
Assert.Equal(m.M32, res.M32, 3);
}

[Fact]
public void Should_Generate_ScaleTransform_x2()
{
LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(
100,
50,
new ScaleTransform() { ScaleX = 2, ScaleY = 2 });

Assert.NotNull(lt.TransformRoot.RenderTransform);

Matrix m = lt.TransformRoot.RenderTransform.Value;
Matrix res = Matrix.CreateScale(2, 2);

Assert.Equal(m.M11, res.M11, 3);
Assert.Equal(m.M12, res.M12, 3);
Assert.Equal(m.M21, res.M21, 3);
Assert.Equal(m.M22, res.M22, 3);
Assert.Equal(m.M31, res.M31, 3);
Assert.Equal(m.M32, res.M32, 3);
}

private static void TransformMeasureSizeTest(Size size, Transform transform, Size expectedSize)
{
LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(
size.Width,
size.Height,
transform);

Size outSize = lt.DesiredSize;

Assert.Equal(outSize.Width, expectedSize.Width);
Assert.Equal(outSize.Height, expectedSize.Height);
}

private static void TransformRootBoundsTest(Size size, Transform transform, Rect expectedBounds)
{
LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(size.Width, size.Height, transform);

Rect outBounds = lt.TransformRoot.Bounds;

Assert.Equal(outBounds.X, expectedBounds.X);
Assert.Equal(outBounds.Y, expectedBounds.Y);
Assert.Equal(outBounds.Width, expectedBounds.Width);
Assert.Equal(outBounds.Height, expectedBounds.Height);
}

private static LayoutTransformControl CreateWithChildAndMeasureAndTransform(
double width,
double height,
Transform transform)
{
var lt = new LayoutTransformControl()
{
LayoutTransform = transform,
Template = new FuncControlTemplate<LayoutTransformControl>(
p => new ContentPresenter() { Content = p.Content })
};

lt.Content = new Rectangle() { Width = width, Height = height };

lt.ApplyTemplate();

//we need to force create visual child
//so the measure after is correct
(lt.Presenter as ContentPresenter).UpdateChild();

Assert.NotNull(lt.Presenter?.Child);

lt.Measure(Size.Infinity);
lt.Arrange(new Rect(lt.DesiredSize));

return lt;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
</Choose>
<ItemGroup>
<Compile Include="ClassesTests.cs" />
<Compile Include="LayoutTransformControlTests.cs" />
<Compile Include="UserControlTests.cs" />
<Compile Include="DockPanelTests.cs" />
<Compile Include="EnumerableExtensions.cs" />
Expand Down

0 comments on commit ba4b3b0

Please sign in to comment.