|
|
@@ -1,13 +1,15 @@
|
|
|
using Avalonia.Media;
|
|
|
+using Avalonia.Metadata;
|
|
|
|
|
|
namespace Avalonia.Controls
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// Viewbox is used to scale single child to fit in the available space.
|
|
|
/// </summary>
|
|
|
- /// <seealso cref="Avalonia.Controls.Decorator" />
|
|
|
- public class Viewbox : Decorator
|
|
|
+ public class Viewbox : Control
|
|
|
{
|
|
|
+ private Decorator _containerVisual;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Defines the <see cref="Stretch"/> property.
|
|
|
/// </summary>
|
|
|
@@ -20,12 +22,27 @@ namespace Avalonia.Controls
|
|
|
public static readonly StyledProperty<StretchDirection> StretchDirectionProperty =
|
|
|
AvaloniaProperty.Register<Viewbox, StretchDirection>(nameof(StretchDirection), StretchDirection.Both);
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Defines the <see cref="Child"/> property
|
|
|
+ /// </summary>
|
|
|
+ public static readonly StyledProperty<IControl?> ChildProperty =
|
|
|
+ Decorator.ChildProperty.AddOwner<Viewbox>();
|
|
|
+
|
|
|
static Viewbox()
|
|
|
{
|
|
|
ClipToBoundsProperty.OverrideDefaultValue<Viewbox>(true);
|
|
|
+ UseLayoutRoundingProperty.OverrideDefaultValue<Viewbox>(true);
|
|
|
AffectsMeasure<Viewbox>(StretchProperty, StretchDirectionProperty);
|
|
|
}
|
|
|
|
|
|
+ public Viewbox()
|
|
|
+ {
|
|
|
+ _containerVisual = new Decorator();
|
|
|
+ _containerVisual.RenderTransformOrigin = RelativePoint.TopLeft;
|
|
|
+ LogicalChildren.Add(_containerVisual);
|
|
|
+ VisualChildren.Add(_containerVisual);
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Gets or sets the stretch mode,
|
|
|
/// which determines how child fits into the available space.
|
|
|
@@ -45,9 +62,40 @@ namespace Avalonia.Controls
|
|
|
set => SetValue(StretchDirectionProperty, value);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Gets or sets the child of the Viewbox
|
|
|
+ /// </summary>
|
|
|
+ [Content]
|
|
|
+ public IControl? Child
|
|
|
+ {
|
|
|
+ get => GetValue(ChildProperty);
|
|
|
+ set => SetValue(ChildProperty, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Gets or sets the transform applied to the container visual that
|
|
|
+ /// hosts the child of the Viewbox
|
|
|
+ /// </summary>
|
|
|
+ protected ITransform? InternalTransform
|
|
|
+ {
|
|
|
+ get => _containerVisual.RenderTransform;
|
|
|
+ set => _containerVisual.RenderTransform = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
|
|
|
+ {
|
|
|
+ base.OnPropertyChanged(change);
|
|
|
+
|
|
|
+ if (change.Property == ChildProperty)
|
|
|
+ {
|
|
|
+ _containerVisual.Child = change.NewValue.GetValueOrDefault<IControl>();
|
|
|
+ InvalidateMeasure();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
|
|
{
|
|
|
- var child = Child;
|
|
|
+ var child = _containerVisual;
|
|
|
|
|
|
if (child != null)
|
|
|
{
|
|
|
@@ -57,7 +105,7 @@ namespace Avalonia.Controls
|
|
|
|
|
|
var size = Stretch.CalculateSize(availableSize, childSize, StretchDirection);
|
|
|
|
|
|
- return size.Constrain(availableSize);
|
|
|
+ return size;
|
|
|
}
|
|
|
|
|
|
return new Size();
|
|
|
@@ -65,31 +113,21 @@ namespace Avalonia.Controls
|
|
|
|
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|
|
{
|
|
|
- var child = Child;
|
|
|
+ var child = _containerVisual;
|
|
|
|
|
|
if (child != null)
|
|
|
{
|
|
|
var childSize = child.DesiredSize;
|
|
|
var scale = Stretch.CalculateScaling(finalSize, childSize, StretchDirection);
|
|
|
|
|
|
- // TODO: Viewbox should have another decorator as a child so we won't affect other render transforms.
|
|
|
- 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;
|
|
|
+ InternalTransform = new ScaleTransform(scale.X, scale.Y);
|
|
|
|
|
|
child.Arrange(new Rect(childSize));
|
|
|
|
|
|
return childSize * scale;
|
|
|
}
|
|
|
|
|
|
- return new Size();
|
|
|
+ return finalSize;
|
|
|
}
|
|
|
}
|
|
|
}
|