diff --git a/readme.md b/readme.md
index 9f16405726..3f4840fce2 100644
--- a/readme.md
+++ b/readme.md
@@ -7,7 +7,7 @@
A multi-platform .NET UI framework. It can run on Windows, Linux, Mac OS X, iOS and Android.
-
+[](https://youtu.be/wHcB3sGLVYg)
Desktop platforms:
@@ -36,7 +36,7 @@ Try out the ControlCatalog to give it a quick demo.
Avalonia is a multi-platform windowing toolkit - somewhat like WPF - that is intended to be multi-
platform. It supports XAML, lookless controls and a flexible styling system, and runs on Windows
-using Direct2D and other operating systems using Gtk & Cairo.
+using Direct2D and other operating systems using Skia and OS-specific windowing backend (GTK, Cocoa, etc).
## Current Status
diff --git a/samples/ControlCatalog/Assets/test_icon.ico b/samples/ControlCatalog/Assets/test_icon.ico
index 9d1074ad13..da8d49ff9b 100644
Binary files a/samples/ControlCatalog/Assets/test_icon.ico and b/samples/ControlCatalog/Assets/test_icon.ico differ
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index 340905a7f7..11ff531514 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -69,6 +69,9 @@
Designer
+
+ Designer
+
Designer
@@ -131,6 +134,9 @@
MenuPage.xaml
+
+ ProgressBarPage.xaml
+
RadioButtonPage.xaml
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 6c432a90ac..0940316ce9 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -16,6 +16,7 @@
+
diff --git a/samples/ControlCatalog/Pages/ProgressBarPage.xaml b/samples/ControlCatalog/Pages/ProgressBarPage.xaml
new file mode 100644
index 0000000000..bf40e68630
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ProgressBarPage.xaml
@@ -0,0 +1,24 @@
+
+
+ ProgressBar
+ A progress bar control
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs b/samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs
new file mode 100644
index 0000000000..56792b3908
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs
@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public class ProgressBarPage : UserControl
+ {
+ public ProgressBarPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/Orientation.cs b/src/Avalonia.Controls/Orientation.cs
new file mode 100644
index 0000000000..fe998c024a
--- /dev/null
+++ b/src/Avalonia.Controls/Orientation.cs
@@ -0,0 +1,21 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Defines vertical or horizontal orientation.
+ ///
+ public enum Orientation
+ {
+ ///
+ /// Horizontal orientation.
+ ///
+ Horizontal,
+
+ ///
+ /// Vertical orientation.
+ ///
+ Vertical,
+ }
+}
diff --git a/src/Avalonia.Controls/Primitives/ScrollBar.cs b/src/Avalonia.Controls/Primitives/ScrollBar.cs
index 0f69e4e5bc..009e1d0ab8 100644
--- a/src/Avalonia.Controls/Primitives/ScrollBar.cs
+++ b/src/Avalonia.Controls/Primitives/ScrollBar.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Controls.Primitives
/// Defines the property.
///
public static readonly StyledProperty OrientationProperty =
- AvaloniaProperty.Register(nameof(Orientation));
+ AvaloniaProperty.Register(nameof(Orientation), Orientation.Vertical);
private Button _lineUpButton;
private Button _lineDownButton;
diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs
index a31a27ddfe..0ff3a78c1f 100644
--- a/src/Avalonia.Controls/ProgressBar.cs
+++ b/src/Avalonia.Controls/ProgressBar.cs
@@ -1,8 +1,12 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
+using System;
+using System.Reactive.Linq;
+
+using Avalonia.Animation;
using Avalonia.Controls.Primitives;
-using Avalonia.Controls.Templates;
+using Avalonia.Layout;
namespace Avalonia.Controls
{
@@ -11,11 +15,38 @@ namespace Avalonia.Controls
///
public class ProgressBar : RangeBase
{
+ public static readonly StyledProperty IsIndeterminateProperty =
+ AvaloniaProperty.Register(nameof(IsIndeterminate));
+
+ public static readonly StyledProperty OrientationProperty =
+ AvaloniaProperty.Register(nameof(Orientation), Orientation.Horizontal);
+
private Border _indicator;
+ private IndeterminateAnimation _indeterminateAnimation;
static ProgressBar()
{
ValueProperty.Changed.AddClassHandler(x => x.ValueChanged);
+
+ HorizontalAlignmentProperty.OverrideDefaultValue(HorizontalAlignment.Left);
+ VerticalAlignmentProperty.OverrideDefaultValue(VerticalAlignment.Top);
+
+ IsIndeterminateProperty.Changed.AddClassHandler(
+ (p, e) => { if (p._indicator != null) p.UpdateIsIndeterminate((bool)e.NewValue); });
+ OrientationProperty.Changed.AddClassHandler(
+ (p, e) => { if (p._indicator != null) p.UpdateOrientation((Orientation)e.NewValue); });
+ }
+
+ public bool IsIndeterminate
+ {
+ get => GetValue(IsIndeterminateProperty);
+ set => SetValue(IsIndeterminateProperty, value);
+ }
+
+ public Orientation Orientation
+ {
+ get => GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
}
///
@@ -29,21 +60,123 @@ namespace Avalonia.Controls
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
_indicator = e.NameScope.Get("PART_Indicator");
+
UpdateIndicator(Bounds.Size);
+ UpdateOrientation(Orientation);
+ UpdateIsIndeterminate(IsIndeterminate);
}
private void UpdateIndicator(Size bounds)
{
if (_indicator != null)
{
- double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
- _indicator.Width = bounds.Width * percent;
+ if (IsIndeterminate)
+ {
+ if (Orientation == Orientation.Horizontal)
+ _indicator.Width = bounds.Width / 5.0;
+ else
+ _indicator.Height = bounds.Height / 5.0;
+ }
+ else
+ {
+ double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
+
+ if (Orientation == Orientation.Horizontal)
+ _indicator.Width = bounds.Width * percent;
+ else
+ _indicator.Height = bounds.Height * percent;
+ }
+ }
+ }
+
+ private void UpdateOrientation(Orientation orientation)
+ {
+ if (orientation == Orientation.Horizontal)
+ {
+ MinHeight = 14;
+ MinWidth = 200;
+
+ _indicator.HorizontalAlignment = HorizontalAlignment.Left;
+ _indicator.VerticalAlignment = VerticalAlignment.Stretch;
+ }
+ else
+ {
+ MinHeight = 200;
+ MinWidth = 14;
+
+ _indicator.HorizontalAlignment = HorizontalAlignment.Stretch;
+ _indicator.VerticalAlignment = VerticalAlignment.Bottom;
}
}
+ private void UpdateIsIndeterminate(bool isIndeterminate)
+ {
+ if (isIndeterminate)
+ if (_indeterminateAnimation == null || _indeterminateAnimation.Disposed)
+ _indeterminateAnimation = IndeterminateAnimation.StartAnimation(this);
+ else
+ _indeterminateAnimation?.Dispose();
+ }
+
private void ValueChanged(AvaloniaPropertyChangedEventArgs e)
{
UpdateIndicator(Bounds.Size);
}
+
+ private class IndeterminateAnimation : IDisposable
+ {
+ private WeakReference _progressBar;
+ private IDisposable _indeterminateBindSubscription;
+ private TimeSpan _startTime;
+ private bool _disposed;
+
+ public bool Disposed => _disposed;
+
+ private IndeterminateAnimation(ProgressBar progressBar)
+ {
+ _progressBar = new WeakReference(progressBar);
+ _startTime = Animate.Stopwatch.Elapsed;
+ _indeterminateBindSubscription = Animate.Timer.TakeWhile(x => (x - _startTime).TotalSeconds <= 4.0)
+ .Select(GetAnimationRect)
+ .Finally(() => _startTime = Animate.Stopwatch.Elapsed)
+ .Repeat()
+ .Subscribe(AnimationTick);
+ }
+
+ public static IndeterminateAnimation StartAnimation(ProgressBar progressBar)
+ {
+ return new IndeterminateAnimation(progressBar);
+ }
+
+ private Rect GetAnimationRect(TimeSpan time)
+ {
+ if (_progressBar.TryGetTarget(out var progressBar))
+ {
+ if (progressBar.Orientation == Orientation.Horizontal)
+ return new Rect(-progressBar._indicator.Width - 5 + (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Width + progressBar._indicator.Width + 10), 0, progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
+ else
+ return new Rect(0, progressBar.Bounds.Height + 5 - (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Height + progressBar._indicator.Height + 10), progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
+ }
+ else
+ {
+ _indeterminateBindSubscription.Dispose();
+ return Rect.Empty;
+ }
+ }
+
+ private void AnimationTick(Rect rect)
+ {
+ if (_progressBar.TryGetTarget(out var progressBar))
+ progressBar._indicator.Arrange(rect);
+ else
+ _indeterminateBindSubscription.Dispose();
+ }
+
+ public void Dispose()
+ {
+ _indeterminateBindSubscription?.Dispose();
+ _disposed = true;
+ }
+ }
}
}
diff --git a/src/Avalonia.Controls/StackPanel.cs b/src/Avalonia.Controls/StackPanel.cs
index 26a755e5f1..0e12fb3283 100644
--- a/src/Avalonia.Controls/StackPanel.cs
+++ b/src/Avalonia.Controls/StackPanel.cs
@@ -6,22 +6,6 @@ using Avalonia.Input;
namespace Avalonia.Controls
{
- ///
- /// Defines vertical or horizontal orientation.
- ///
- public enum Orientation
- {
- ///
- /// Vertical orientation.
- ///
- Vertical,
-
- ///
- /// Horizontal orientation.
- ///
- Horizontal,
- }
-
///
/// A panel which lays out its children horizontally or vertically.
///
@@ -37,7 +21,7 @@ namespace Avalonia.Controls
/// Defines the property.
///
public static readonly StyledProperty OrientationProperty =
- AvaloniaProperty.Register(nameof(Orientation));
+ AvaloniaProperty.Register(nameof(Orientation), Orientation.Vertical);
///
/// Initializes static members of the class.
diff --git a/src/Avalonia.Themes.Default/ProgressBar.xaml b/src/Avalonia.Themes.Default/ProgressBar.xaml
index 4acff26537..82f385e16b 100644
--- a/src/Avalonia.Themes.Default/ProgressBar.xaml
+++ b/src/Avalonia.Themes.Default/ProgressBar.xaml
@@ -1,8 +1,6 @@