diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index 020fb2fff3..f3ec7b48aa 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -39,6 +39,10 @@ namespace ControlCatalog
public static Styles DefaultLight = new Styles
{
+ new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+ {
+ Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
+ },
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")
@@ -60,6 +64,10 @@ namespace ControlCatalog
public static Styles DefaultDark = new Styles
{
+ new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+ {
+ Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
+ },
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")
diff --git a/samples/ControlCatalog/Pages/ViewboxPage.xaml b/samples/ControlCatalog/Pages/ViewboxPage.xaml
index e78cf2bc22..ef802db33e 100644
--- a/samples/ControlCatalog/Pages/ViewboxPage.xaml
+++ b/samples/ControlCatalog/Pages/ViewboxPage.xaml
@@ -1,66 +1,36 @@
-
-
- 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
-
-
-
+
Viewbox
A control used to scale single child.
-
- None
- Fill
- Uniform
- UniformToFill
-
- Hello World!
-
-
- Hello World!
-
-
- Hello World!
-
-
- Hello World!
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/ViewboxPage.xaml.cs b/samples/ControlCatalog/Pages/ViewboxPage.xaml.cs
index 1b5f4bc7f4..94b3f3ea14 100644
--- a/samples/ControlCatalog/Pages/ViewboxPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ViewboxPage.xaml.cs
@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
+using Avalonia.Media;
namespace ControlCatalog.Pages
{
@@ -7,7 +8,25 @@ namespace ControlCatalog.Pages
{
public ViewboxPage()
{
- this.InitializeComponent();
+ InitializeComponent();
+
+ var stretchSelector = this.FindControl("StretchSelector");
+
+ stretchSelector.Items = new[]
+ {
+ Stretch.Uniform, Stretch.UniformToFill, Stretch.Fill, Stretch.None
+ };
+
+ stretchSelector.SelectedIndex = 0;
+
+ var stretchDirectionSelector = this.FindControl("StretchDirectionSelector");
+
+ stretchDirectionSelector.Items = new[]
+ {
+ StretchDirection.Both, StretchDirection.DownOnly, StretchDirection.UpOnly
+ };
+
+ stretchDirectionSelector.SelectedIndex = 0;
}
private void InitializeComponent()
diff --git a/samples/RenderDemo/Pages/AnimationsPage.xaml b/samples/RenderDemo/Pages/AnimationsPage.xaml
index 12fb31ea59..21c7d68b5d 100644
--- a/samples/RenderDemo/Pages/AnimationsPage.xaml
+++ b/samples/RenderDemo/Pages/AnimationsPage.xaml
@@ -1,7 +1,8 @@
+ x:Class="RenderDemo.Pages.AnimationsPage"
+ MaxWidth="600">
@@ -167,8 +168,8 @@
-
- Hover to activate Transform Keyframe Animations.
+
+ Hover to activate Keyframe Animations.
diff --git a/samples/RenderDemo/Pages/TransitionsPage.xaml b/samples/RenderDemo/Pages/TransitionsPage.xaml
index d6da293ff3..f9f69fb341 100644
--- a/samples/RenderDemo/Pages/TransitionsPage.xaml
+++ b/samples/RenderDemo/Pages/TransitionsPage.xaml
@@ -1,7 +1,8 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:Class="RenderDemo.Pages.TransitionsPage"
+ MaxWidth="600">
@@ -90,6 +91,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -98,8 +149,8 @@
-
- Hover to activate Transform Keyframe Animations.
+
+ Hover to activate Transitions.
@@ -109,6 +160,12 @@
+
+
+
+
+
+
diff --git a/src/Avalonia.Animation/Transitions/DoubleTransition.cs b/src/Avalonia.Animation/Transitions/DoubleTransition.cs
index 8cae1e1f81..d5bb1aac20 100644
--- a/src/Avalonia.Animation/Transitions/DoubleTransition.cs
+++ b/src/Avalonia.Animation/Transitions/DoubleTransition.cs
@@ -1,6 +1,8 @@
using System;
using System.Reactive.Linq;
+using Avalonia.Animation.Animators;
+
namespace Avalonia.Animation
{
///
@@ -8,15 +10,13 @@ namespace Avalonia.Animation
///
public class DoubleTransition : Transition
{
+ private static readonly DoubleAnimator s_animator = new DoubleAnimator();
+
///
public override IObservable DoTransition(IObservable progress, double oldValue, double newValue)
{
return progress
- .Select(p =>
- {
- var f = Easing.Ease(p);
- return ((newValue - oldValue) * f) + oldValue;
- });
+ .Select(progress => s_animator.Interpolate(Easing.Ease(progress), oldValue, newValue));
}
}
}
diff --git a/src/Avalonia.Animation/Transitions/FloatTransition.cs b/src/Avalonia.Animation/Transitions/FloatTransition.cs
index 427563e559..37b644fa96 100644
--- a/src/Avalonia.Animation/Transitions/FloatTransition.cs
+++ b/src/Avalonia.Animation/Transitions/FloatTransition.cs
@@ -1,6 +1,8 @@
using System;
using System.Reactive.Linq;
+using Avalonia.Animation.Animators;
+
namespace Avalonia.Animation
{
///
@@ -8,12 +10,13 @@ namespace Avalonia.Animation
///
public class FloatTransition : Transition
{
+ private static readonly FloatAnimator s_animator = new FloatAnimator();
+
///
public override IObservable DoTransition(IObservable progress, float oldValue, float newValue)
{
- var delta = newValue - oldValue;
return progress
- .Select(p => (float)Easing.Ease(p) * delta + oldValue);
+ .Select(progress => s_animator.Interpolate(Easing.Ease(progress), oldValue, newValue));
}
}
}
diff --git a/src/Avalonia.Animation/Transitions/IntegerTransition.cs b/src/Avalonia.Animation/Transitions/IntegerTransition.cs
index 7a85bd75dc..223b2ba531 100644
--- a/src/Avalonia.Animation/Transitions/IntegerTransition.cs
+++ b/src/Avalonia.Animation/Transitions/IntegerTransition.cs
@@ -1,6 +1,8 @@
using System;
using System.Reactive.Linq;
+using Avalonia.Animation.Animators;
+
namespace Avalonia.Animation
{
///
@@ -8,12 +10,13 @@ namespace Avalonia.Animation
///
public class IntegerTransition : Transition
{
+ private static readonly Int32Animator s_animator = new Int32Animator();
+
///
public override IObservable DoTransition(IObservable progress, int oldValue, int newValue)
{
- var delta = newValue - oldValue;
return progress
- .Select(p => (int)(Easing.Ease(p) * delta + oldValue));
+ .Select(progress => s_animator.Interpolate(Easing.Ease(progress), oldValue, newValue));
}
}
}
diff --git a/src/Avalonia.Base/PropertyStore/BindingEntry.cs b/src/Avalonia.Base/PropertyStore/BindingEntry.cs
index 1b29338f07..362736eb06 100644
--- a/src/Avalonia.Base/PropertyStore/BindingEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/BindingEntry.cs
@@ -79,7 +79,7 @@ namespace Avalonia.PropertyStore
public void OnError(Exception error)
{
- throw new NotImplementedException();
+ throw new NotImplementedException("BindingEntry.OnError is not implemented", error);
}
public void OnNext(BindingValue value)
diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs
index a070a1b9d7..1b4632d368 100644
--- a/src/Avalonia.Controls.DataGrid/DataGrid.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs
@@ -535,7 +535,8 @@ namespace Avalonia.Controls
AvaloniaProperty.RegisterDirect(
nameof(SelectedIndex),
o => o.SelectedIndex,
- (o, v) => o.SelectedIndex = v);
+ (o, v) => o.SelectedIndex = v,
+ defaultBindingMode: BindingMode.TwoWay);
///
/// Gets or sets the index of the current selection.
@@ -553,7 +554,8 @@ namespace Avalonia.Controls
AvaloniaProperty.RegisterDirect(
nameof(SelectedItem),
o => o.SelectedItem,
- (o, v) => o.SelectedItem = v);
+ (o, v) => o.SelectedItem = v,
+ defaultBindingMode: BindingMode.TwoWay);
///
/// Gets or sets the data item corresponding to the selected row.
diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt
index 7199c15d21..a79b3b4d7b 100644
--- a/src/Avalonia.Controls/ApiCompatBaseline.txt
+++ b/src/Avalonia.Controls/ApiCompatBaseline.txt
@@ -4,10 +4,11 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalon
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.IMenuItem.StaysOpenOnClick.set(System.Boolean)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseClosed()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseOpening()' is present in the implementation but not in the contract.
+MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Viewbox.StretchProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Notifications.NotificationCard.CloseOnClickProperty' does not exist in the implementation but it does exist in the contract.
EnumValuesMustMatch : Enum value 'Avalonia.Platform.ExtendClientAreaChromeHints Avalonia.Platform.ExtendClientAreaChromeHints.Default' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.ICursorImpl)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 11
+Total Issues: 12
diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs
index 247b62d3cf..c448729643 100644
--- a/src/Avalonia.Controls/Image.cs
+++ b/src/Avalonia.Controls/Image.cs
@@ -31,8 +31,8 @@ namespace Avalonia.Controls
static Image()
{
- AffectsRender(SourceProperty, StretchProperty);
- AffectsMeasure(SourceProperty, StretchProperty);
+ AffectsRender(SourceProperty, StretchProperty, StretchDirectionProperty);
+ AffectsMeasure(SourceProperty, StretchProperty, StretchDirectionProperty);
}
///
diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs
index 781c93bcbe..624c61bb82 100644
--- a/src/Avalonia.Controls/Viewbox.cs
+++ b/src/Avalonia.Controls/Viewbox.cs
@@ -1,40 +1,48 @@
-using System;
-using Avalonia.Media;
+using Avalonia.Media;
namespace Avalonia.Controls
{
///
- /// Viewbox is used to scale single child.
+ /// Viewbox is used to scale single child to fit in the available space.
///
///
public class Viewbox : Decorator
{
///
- /// The stretch property
+ /// Defines the property.
///
- public static readonly AvaloniaProperty StretchProperty =
- AvaloniaProperty.RegisterDirect(nameof(Stretch),
- v => v.Stretch, (c, v) => c.Stretch = v, Stretch.Uniform);
+ public static readonly StyledProperty StretchProperty =
+ AvaloniaProperty.Register(nameof(Stretch), Stretch.Uniform);
- private Stretch _stretch = Stretch.Uniform;
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty StretchDirectionProperty =
+ AvaloniaProperty.Register(nameof(StretchDirection), StretchDirection.Both);
+
+ static Viewbox()
+ {
+ ClipToBoundsProperty.OverrideDefaultValue(true);
+ AffectsMeasure(StretchProperty, StretchDirectionProperty);
+ }
///
/// Gets or sets the stretch mode,
/// which determines how child fits into the available space.
///
- ///
- /// The stretch.
- ///
public Stretch Stretch
{
- get => _stretch;
- set => SetAndRaise(StretchProperty, ref _stretch, value);
+ get => GetValue(StretchProperty);
+ set => SetValue(StretchProperty, value);
}
- static Viewbox()
+ ///
+ /// Gets or sets a value controlling in what direction contents will be stretched.
+ ///
+ public StretchDirection StretchDirection
{
- ClipToBoundsProperty.OverrideDefaultValue(true);
- AffectsMeasure(StretchProperty);
+ get => GetValue(StretchDirectionProperty);
+ set => SetValue(StretchDirectionProperty, value);
}
protected override Size MeasureOverride(Size availableSize)
@@ -47,9 +55,9 @@ namespace Avalonia.Controls
var childSize = child.DesiredSize;
- var scale = GetScale(availableSize, childSize, Stretch);
+ var size = Stretch.CalculateSize(availableSize, childSize, StretchDirection);
- return (childSize * scale).Constrain(availableSize);
+ return size.Constrain(availableSize);
}
return new Size();
@@ -62,7 +70,9 @@ namespace Avalonia.Controls
if (child != null)
{
var childSize = child.DesiredSize;
- var scale = GetScale(finalSize, childSize, Stretch);
+ 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)
@@ -81,44 +91,5 @@ namespace Avalonia.Controls
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);
- }
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs
index fd2e4c3355..ef227f7374 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs
@@ -1,4 +1,6 @@
+using System;
using System.ComponentModel;
+using System.Text;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.VisualTree;
@@ -95,12 +97,27 @@ namespace Avalonia.Diagnostics.ViewModels
{
string CreateConstraintInfo(StyledProperty minProperty, StyledProperty maxProperty)
{
- if (ao.IsSet(minProperty) || ao.IsSet(maxProperty))
+ bool hasMin = ao.IsSet(minProperty);
+ bool hasMax = ao.IsSet(maxProperty);
+
+ if (hasMin || hasMax)
{
- var minValue = ao.GetValue(minProperty);
- var maxValue = ao.GetValue(maxProperty);
+ var builder = new StringBuilder();
+
+ if (hasMin)
+ {
+ var minValue = ao.GetValue(minProperty);
+ builder.AppendFormat("Min: {0}", Math.Round(minValue, 2));
+ builder.AppendLine();
+ }
+
+ if (hasMax)
+ {
+ var maxValue = ao.GetValue(maxProperty);
+ builder.AppendFormat("Max: {0}", Math.Round(maxValue, 2));
+ }
- return $"{minValue} < size < {maxValue}";
+ return builder.ToString();
}
return null;
@@ -183,8 +200,8 @@ namespace Avalonia.Diagnostics.ViewModels
{
var size = _control.Bounds;
- Width = size.Width;
- Height = size.Height;
+ Width = Math.Round(size.Width, 2);
+ Height = Math.Round(size.Height, 2);
}
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
index 9ba576c826..50534e77b8 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
@@ -8,11 +8,16 @@
+
+
+
+
+
@@ -24,43 +29,60 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -110,47 +132,67 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ThicknessEditor.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/ThicknessEditor.cs
index c7611c8c46..2f03a23fdf 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/ThicknessEditor.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ThicknessEditor.cs
@@ -1,21 +1,9 @@
using Avalonia.Controls;
using Avalonia.Data;
-using Avalonia.Data.Converters;
using Avalonia.Media;
namespace Avalonia.Diagnostics.Views
{
- internal static class Converters
- {
- public static IValueConverter HasConstraintConverter =
- new FuncValueConverter