1 changed files with 123 additions and 0 deletions
@ -0,0 +1,123 @@ |
|||
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() |
|||
{ |
|||
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); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue