diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 76eca330a9..e40ec12461 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -528,6 +528,7 @@ private:
bool _fullScreenActive;
SystemDecorations _decorations;
AvnWindowState _lastWindowState;
+ AvnWindowState _actualWindowState;
bool _inSetWindowState;
NSRect _preZoomSize;
bool _transitioningWindowState;
@@ -554,6 +555,7 @@ private:
_transitioningWindowState = false;
_inSetWindowState = false;
_lastWindowState = Normal;
+ _actualWindowState = Normal;
WindowEvents = events;
[Window setCanBecomeKeyAndMain];
[Window disableCursorRects];
@@ -648,7 +650,7 @@ private:
void WindowStateChanged () override
{
- if(!_inSetWindowState && !_transitioningWindowState)
+ if(_shown && !_inSetWindowState && !_transitioningWindowState)
{
AvnWindowState state;
GetWindowState(&state);
@@ -978,14 +980,14 @@ private:
{
@autoreleasepool
{
- if(_lastWindowState == state)
+ if(_actualWindowState == state)
{
return S_OK;
}
_inSetWindowState = true;
- auto currentState = _lastWindowState;
+ auto currentState = _actualWindowState;
_lastWindowState = state;
if(currentState == Normal)
@@ -1064,8 +1066,11 @@ private:
}
break;
}
+
+ _actualWindowState = _lastWindowState;
}
+
_inSetWindowState = false;
return S_OK;
diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs
index 723351ae57..2446c0e1c9 100644
--- a/samples/ControlCatalog/MainWindow.xaml.cs
+++ b/samples/ControlCatalog/MainWindow.xaml.cs
@@ -17,7 +17,10 @@ namespace ControlCatalog
public MainWindow()
{
this.InitializeComponent();
- this.AttachDevTools();
+ this.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
+ {
+ StartupScreenIndex = 1,
+ });
//Renderer.DrawFps = true;
//Renderer.DrawDirtyRects = Renderer.DrawFps = true;
diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml
index aa165d13f7..f37df56b73 100644
--- a/samples/RenderDemo/MainWindow.xaml
+++ b/samples/RenderDemo/MainWindow.xaml
@@ -36,6 +36,9 @@
+
+
+
diff --git a/samples/RenderDemo/Pages/CustomAnimatorPage.xaml b/samples/RenderDemo/Pages/CustomAnimatorPage.xaml
new file mode 100644
index 0000000000..b386636cae
--- /dev/null
+++ b/samples/RenderDemo/Pages/CustomAnimatorPage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/RenderDemo/Pages/CustomAnimatorPage.xaml.cs b/samples/RenderDemo/Pages/CustomAnimatorPage.xaml.cs
new file mode 100644
index 0000000000..eed8ee29ce
--- /dev/null
+++ b/samples/RenderDemo/Pages/CustomAnimatorPage.xaml.cs
@@ -0,0 +1,27 @@
+using System.Reactive.Linq;
+using Avalonia;
+using Avalonia.Animation;
+using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
+using Avalonia.Data;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using RenderDemo.ViewModels;
+
+namespace RenderDemo.Pages
+{
+ public class CustomAnimatorPage : UserControl
+ {
+ public CustomAnimatorPage()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/RenderDemo/Pages/CustomStringAnimator.cs b/samples/RenderDemo/Pages/CustomStringAnimator.cs
new file mode 100644
index 0000000000..851a2d0187
--- /dev/null
+++ b/samples/RenderDemo/Pages/CustomStringAnimator.cs
@@ -0,0 +1,16 @@
+using Avalonia.Animation.Animators;
+
+namespace RenderDemo.Pages
+{
+ public class CustomStringAnimator : Animator
+ {
+ public override string Interpolate(double progress, string oldValue, string newValue)
+ {
+ if (newValue.Length == 0) return "";
+ var step = 1.0 / newValue.Length;
+ var length = (int)(progress / step);
+ var result = newValue.Substring(0, length + 1);
+ return result;
+ }
+ }
+}
diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs
index c42153ec4f..daa4793ef0 100644
--- a/src/Avalonia.Animation/Animation.cs
+++ b/src/Avalonia.Animation/Animation.cs
@@ -194,6 +194,33 @@ namespace Avalonia.Animation
[Content]
public KeyFrames Children { get; } = new KeyFrames();
+ // Store values for the Animator attached properties for IAnimationSetter objects.
+ private static readonly Dictionary s_animators = new Dictionary();
+
+ ///
+ /// Gets the value of the Animator attached property for a setter.
+ ///
+ /// The animation setter.
+ /// The property animator type.
+ public static Type GetAnimator(IAnimationSetter setter)
+ {
+ if (s_animators.TryGetValue(setter, out var type))
+ {
+ return type;
+ }
+ return null;
+ }
+
+ ///
+ /// Sets the value of the Animator attached property for a setter.
+ ///
+ /// The animation setter.
+ /// The property animator value.
+ public static void SetAnimator(IAnimationSetter setter, Type value)
+ {
+ s_animators[setter] = value;
+ }
+
private readonly static List<(Func Condition, Type Animator)> Animators = new List<(Func, Type)>
{
( prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator) ),
@@ -248,7 +275,7 @@ namespace Avalonia.Animation
{
foreach (var setter in keyframe.Setters)
{
- var handler = GetAnimatorType(setter.Property);
+ var handler = Animation.GetAnimator(setter) ?? GetAnimatorType(setter.Property);
if (handler == null)
{
diff --git a/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs b/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
index 0e36c8f9cb..2a386f106e 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
@@ -10,7 +10,8 @@ namespace Avalonia.Diagnostics
{
public static class DevTools
{
- private static readonly Dictionary s_open = new Dictionary();
+ private static readonly Dictionary s_open =
+ new Dictionary();
public static IDisposable Attach(TopLevel root, KeyGesture gesture)
{
@@ -52,6 +53,7 @@ namespace Avalonia.Diagnostics
Width = options.Size.Width,
Height = options.Size.Height,
};
+ window.SetOptions(options);
window.Closed += DevToolsClosed;
s_open.Add(root, window);
diff --git a/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs b/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
index f9978f3b7e..5336dca65b 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
@@ -22,5 +22,10 @@ namespace Avalonia.Diagnostics
/// Gets or sets the initial size of the DevTools window. The default value is 1280x720.
///
public Size Size { get; set; } = new Size(1280, 720);
+
+ ///
+ /// Get or set the startup screen index where the DevTools window will be displayed.
+ ///
+ public int? StartupScreenIndex { get; set; }
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
index 72491bebc2..3f367165ac 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
@@ -151,7 +151,7 @@ namespace Avalonia.Diagnostics.ViewModels
get { return _pointerOverElement; }
private set { RaiseAndSetIfChanged(ref _pointerOverElement, value); }
}
-
+
private void UpdateConsoleContext(ConsoleContext context)
{
context.root = _root;
@@ -213,5 +213,12 @@ namespace Avalonia.Diagnostics.ViewModels
tree.SelectControl(control);
}
}
+
+ public int? StartupScreenIndex { get; private set; } = default;
+
+ public void SetOptions(DevToolsOptions options)
+ {
+ StartupScreenIndex = options.StartupScreenIndex;
+ }
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs
index bbb8e76551..d1232b749a 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs
@@ -24,6 +24,23 @@ namespace Avalonia.Diagnostics.Views
_keySubscription = InputManager.Instance.Process
.OfType()
.Subscribe(RawKeyDown);
+
+ EventHandler? lh = default;
+ lh = (s, e) =>
+ {
+ this.Opened -= lh;
+ if ((DataContext as MainViewModel)?.StartupScreenIndex is int index)
+ {
+ var screens = this.Screens;
+ if (index > -1 && index < screens.ScreenCount)
+ {
+ var screen = screens.All[index];
+ this.Position = screen.Bounds.TopLeft;
+ this.WindowState = WindowState.Maximized;
+ }
+ }
+ };
+ this.Opened += lh;
}
public TopLevel? Root
@@ -115,5 +132,8 @@ namespace Avalonia.Diagnostics.Views
}
private void RootClosed(object? sender, EventArgs e) => Close();
+
+ public void SetOptions(DevToolsOptions options) =>
+ (DataContext as MainViewModel)?.SetOptions(options);
}
}