committed by
GitHub
9 changed files with 332 additions and 54 deletions
@ -0,0 +1,65 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
|||
<UserControl.Resources> |
|||
<StreamGeometry x:Key="Acorn"> |
|||
F1 M 16.6309,18.6563C 17.1309, |
|||
8.15625 29.8809,14.1563 29.8809, |
|||
14.1563C 30.8809,11.1563 34.1308, |
|||
11.4063 34.1308,11.4063C 33.5,12 |
|||
34.6309,13.1563 34.6309,13.1563C |
|||
32.1309,13.1562 31.1309,14.9062 |
|||
31.1309,14.9062C 41.1309,23.9062 |
|||
32.6309,27.9063 32.6309,27.9062C |
|||
24.6309,24.9063 21.1309,22.1562 |
|||
16.6309,18.6563 Z M 16.6309,19.9063C |
|||
21.6309,24.1563 25.1309,26.1562 |
|||
31.6309,28.6562C 31.6309,28.6562 |
|||
26.3809,39.1562 18.3809,36.1563C |
|||
18.3809,36.1563 18,38 16.3809,36.9063C |
|||
15,36 16.3809,34.9063 16.3809,34.9063C |
|||
16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z |
|||
</StreamGeometry> |
|||
</UserControl.Resources> |
|||
|
|||
<Grid RowDefinitions="Auto,*"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h1">Viewbox</TextBlock> |
|||
<TextBlock Classes="h2">A control used to scale single child.</TextBlock> |
|||
</StackPanel> |
|||
<Grid ColumnDefinitions="Auto,*,*" |
|||
RowDefinitions="*,*,*,*" |
|||
Grid.Row="1" Margin="48" |
|||
MaxWidth="400"> |
|||
<TextBlock Grid.Row="0" VerticalAlignment="Center">None</TextBlock> |
|||
<TextBlock Grid.Row="1" VerticalAlignment="Center">Fill</TextBlock> |
|||
<TextBlock Grid.Row="2" VerticalAlignment="Center">Uniform</TextBlock> |
|||
<TextBlock Grid.Row="3" VerticalAlignment="Center">UniformToFill</TextBlock> |
|||
|
|||
<Viewbox Grid.Row="0" Grid.Column="1" Stretch="None"> |
|||
<TextBlock>Hello World!</TextBlock> |
|||
</Viewbox> |
|||
<Viewbox Grid.Row="1" Grid.Column="1" Stretch="Fill"> |
|||
<TextBlock>Hello World!</TextBlock> |
|||
</Viewbox> |
|||
<Viewbox Grid.Row="2" Grid.Column="1" Stretch="Uniform"> |
|||
<TextBlock>Hello World!</TextBlock> |
|||
</Viewbox> |
|||
<Viewbox Grid.Row="3" Grid.Column="1" Stretch="UniformToFill"> |
|||
<TextBlock>Hello World!</TextBlock> |
|||
</Viewbox> |
|||
|
|||
<Viewbox Grid.Row="0" Grid.Column="2" Stretch="None"> |
|||
<Path Fill="Blue" Data="{StaticResource Acorn}"/> |
|||
</Viewbox> |
|||
<Viewbox Grid.Row="1" Grid.Column="2" Stretch="Fill"> |
|||
<Path Fill="Blue" Data="{StaticResource Acorn}"/> |
|||
</Viewbox> |
|||
<Viewbox Grid.Row="2" Grid.Column="2" Stretch="Uniform"> |
|||
<Path Fill="Blue" Data="{StaticResource Acorn}"/> |
|||
</Viewbox> |
|||
<Viewbox Grid.Row="3" Grid.Column="2" Stretch="UniformToFill"> |
|||
<Path Fill="Blue" Data="{StaticResource Acorn}"/> |
|||
</Viewbox> |
|||
</Grid> |
|||
</Grid> |
|||
</UserControl> |
|||
@ -0,0 +1,18 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ViewboxPage : UserControl |
|||
{ |
|||
public ViewboxPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,124 @@ |
|||
using System; |
|||
using Avalonia.Media; |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// Viewbox is used to scale single child.
|
|||
/// </summary>
|
|||
/// <seealso cref="Avalonia.Controls.Decorator" />
|
|||
public class Viewbox : Decorator |
|||
{ |
|||
/// <summary>
|
|||
/// The stretch property
|
|||
/// </summary>
|
|||
public static AvaloniaProperty<Stretch> StretchProperty = |
|||
AvaloniaProperty.RegisterDirect<Viewbox, Stretch>(nameof(Stretch), |
|||
v => v.Stretch, (c, v) => c.Stretch = v, Stretch.Uniform); |
|||
|
|||
private Stretch _stretch = Stretch.Uniform; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the stretch mode,
|
|||
/// which determines how child fits into the available space.
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// The stretch.
|
|||
/// </value>
|
|||
public Stretch Stretch |
|||
{ |
|||
get => _stretch; |
|||
set => SetAndRaise(StretchProperty, ref _stretch, value); |
|||
} |
|||
|
|||
static Viewbox() |
|||
{ |
|||
ClipToBoundsProperty.OverrideDefaultValue<Viewbox>(true); |
|||
AffectsMeasure<Viewbox>(StretchProperty); |
|||
} |
|||
|
|||
protected override Size MeasureOverride(Size availableSize) |
|||
{ |
|||
var child = Child; |
|||
|
|||
if (child != null) |
|||
{ |
|||
child.Measure(Size.Infinity); |
|||
|
|||
var childSize = child.DesiredSize; |
|||
|
|||
var scale = GetScale(availableSize, childSize, Stretch); |
|||
|
|||
return childSize * scale; |
|||
} |
|||
|
|||
return new Size(); |
|||
} |
|||
|
|||
protected override Size ArrangeOverride(Size finalSize) |
|||
{ |
|||
var child = Child; |
|||
|
|||
if (child != null) |
|||
{ |
|||
var childSize = child.DesiredSize; |
|||
var scale = GetScale(finalSize, childSize, Stretch); |
|||
var scaleTransform = child.RenderTransform as ScaleTransform; |
|||
|
|||
if (scaleTransform == null) |
|||
{ |
|||
child.RenderTransform = scaleTransform = new ScaleTransform(scale.X, scale.Y); |
|||
child.RenderTransformOrigin = RelativePoint.TopLeft; |
|||
} |
|||
|
|||
scaleTransform.ScaleX = scale.X; |
|||
scaleTransform.ScaleY = scale.Y; |
|||
|
|||
child.Arrange(new Rect(childSize)); |
|||
|
|||
return childSize * scale; |
|||
} |
|||
|
|||
return new Size(); |
|||
} |
|||
|
|||
private static Vector GetScale(Size availableSize, Size childSize, Stretch stretch) |
|||
{ |
|||
double scaleX = 1.0; |
|||
double scaleY = 1.0; |
|||
|
|||
bool validWidth = !double.IsPositiveInfinity(availableSize.Width); |
|||
bool validHeight = !double.IsPositiveInfinity(availableSize.Height); |
|||
|
|||
if (stretch != Stretch.None && (validWidth || validHeight)) |
|||
{ |
|||
scaleX = childSize.Width <= 0.0 ? 0.0 : availableSize.Width / childSize.Width; |
|||
scaleY = childSize.Height <= 0.0 ? 0.0 : availableSize.Height / childSize.Height; |
|||
|
|||
if (!validWidth) |
|||
{ |
|||
scaleX = scaleY; |
|||
} |
|||
else if (!validHeight) |
|||
{ |
|||
scaleY = scaleX; |
|||
} |
|||
else |
|||
{ |
|||
switch (stretch) |
|||
{ |
|||
case Stretch.Uniform: |
|||
scaleX = scaleY = Math.Min(scaleX, scaleY); |
|||
break; |
|||
|
|||
case Stretch.UniformToFill: |
|||
scaleX = scaleY = Math.Max(scaleX, scaleY); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return new Vector(scaleX, scaleY); |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
<Style xmlns="https://github.com/avaloniaui" Selector="LayoutTransformControl"> |
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<ContentPresenter Name="PART_ContentPresenter" |
|||
Background="{TemplateBinding Background}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
ContentTemplate="{TemplateBinding ContentTemplate}" |
|||
Content="{TemplateBinding Content}" |
|||
Padding="{TemplateBinding Padding}"/> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
</Style> |
|||
@ -0,0 +1,105 @@ |
|||
using Avalonia.Controls.Shapes; |
|||
using Avalonia.Media; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Controls.UnitTests |
|||
{ |
|||
public class ViewboxTests |
|||
{ |
|||
[Fact] |
|||
public void Viewbox_Stretch_Uniform_Child() |
|||
{ |
|||
var target = new Viewbox() { Child = new Rectangle() { Width = 100, Height = 50 } }; |
|||
|
|||
target.Measure(new Size(200, 200)); |
|||
target.Arrange(new Rect(new Point(0, 0), target.DesiredSize)); |
|||
|
|||
Assert.Equal(new Size(200, 100), target.DesiredSize); |
|||
var scaleTransform = target.Child.RenderTransform as ScaleTransform; |
|||
|
|||
Assert.NotNull(scaleTransform); |
|||
Assert.Equal(2.0, scaleTransform.ScaleX); |
|||
Assert.Equal(2.0, scaleTransform.ScaleY); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Viewbox_Stretch_None_Child() |
|||
{ |
|||
var target = new Viewbox() { Stretch = Stretch.None, Child = new Rectangle() { Width = 100, Height = 50 } }; |
|||
|
|||
target.Measure(new Size(200, 200)); |
|||
target.Arrange(new Rect(new Point(0, 0), target.DesiredSize)); |
|||
|
|||
Assert.Equal(new Size(100, 50), target.DesiredSize); |
|||
var scaleTransform = target.Child.RenderTransform as ScaleTransform; |
|||
|
|||
Assert.NotNull(scaleTransform); |
|||
Assert.Equal(1.0, scaleTransform.ScaleX); |
|||
Assert.Equal(1.0, scaleTransform.ScaleY); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Viewbox_Stretch_Fill_Child() |
|||
{ |
|||
var target = new Viewbox() { Stretch = Stretch.Fill, Child = new Rectangle() { Width = 100, Height = 50 } }; |
|||
|
|||
target.Measure(new Size(200, 200)); |
|||
target.Arrange(new Rect(new Point(0, 0), target.DesiredSize)); |
|||
|
|||
Assert.Equal(new Size(200, 200), target.DesiredSize); |
|||
var scaleTransform = target.Child.RenderTransform as ScaleTransform; |
|||
|
|||
Assert.NotNull(scaleTransform); |
|||
Assert.Equal(2.0, scaleTransform.ScaleX); |
|||
Assert.Equal(4.0, scaleTransform.ScaleY); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Viewbox_Stretch_UniformToFill_Child() |
|||
{ |
|||
var target = new Viewbox() { Stretch = Stretch.UniformToFill, Child = new Rectangle() { Width = 100, Height = 50 } }; |
|||
|
|||
target.Measure(new Size(200, 200)); |
|||
target.Arrange(new Rect(new Point(0, 0), target.DesiredSize)); |
|||
|
|||
Assert.Equal(new Size(200, 200), target.DesiredSize); |
|||
var scaleTransform = target.Child.RenderTransform as ScaleTransform; |
|||
|
|||
Assert.NotNull(scaleTransform); |
|||
Assert.Equal(4.0, scaleTransform.ScaleX); |
|||
Assert.Equal(4.0, scaleTransform.ScaleY); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Viewbox_Stretch_Uniform_Child_With_Unrestricted_Width() |
|||
{ |
|||
var target = new Viewbox() { Child = new Rectangle() { Width = 100, Height = 50 } }; |
|||
|
|||
target.Measure(new Size(double.PositiveInfinity, 200)); |
|||
target.Arrange(new Rect(new Point(0, 0), target.DesiredSize)); |
|||
|
|||
Assert.Equal(new Size(400, 200), target.DesiredSize); |
|||
var scaleTransform = target.Child.RenderTransform as ScaleTransform; |
|||
|
|||
Assert.NotNull(scaleTransform); |
|||
Assert.Equal(4.0, scaleTransform.ScaleX); |
|||
Assert.Equal(4.0, scaleTransform.ScaleY); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Viewbox_Stretch_Uniform_Child_With_Unrestricted_Height() |
|||
{ |
|||
var target = new Viewbox() { Child = new Rectangle() { Width = 100, Height = 50 } }; |
|||
|
|||
target.Measure(new Size(200, double.PositiveInfinity)); |
|||
target.Arrange(new Rect(new Point(0, 0), target.DesiredSize)); |
|||
|
|||
Assert.Equal(new Size(200, 100), target.DesiredSize); |
|||
var scaleTransform = target.Child.RenderTransform as ScaleTransform; |
|||
|
|||
Assert.NotNull(scaleTransform); |
|||
Assert.Equal(2.0, scaleTransform.ScaleX); |
|||
Assert.Equal(2.0, scaleTransform.ScaleY); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue