Browse Source

Merge pull request #11555 from AvaloniaUI/feature/progressbar-cleanup

ProgressBar refactoring/cleanup.
pull/11563/head
Jumar Macato 3 years ago
committed by GitHub
parent
commit
19d285b76d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 284
      src/Avalonia.Controls/ProgressBar.cs
  2. 8
      src/Avalonia.Themes.Simple/Controls/ProgressBar.xaml

284
src/Avalonia.Controls/ProgressBar.cs

@ -31,77 +31,157 @@ namespace Avalonia.Controls
private double _containerAnimationEndPosition; private double _containerAnimationEndPosition;
private double _container2AnimationStartPosition; private double _container2AnimationStartPosition;
private double _container2AnimationEndPosition; private double _container2AnimationEndPosition;
private double _indeterminateStartingOffset;
public static readonly DirectProperty<ProgressBarTemplateSettings, double> ContainerAnimationStartPositionProperty = private double _indeterminateEndingOffset;
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(ContainerAnimationStartPosition), /// <summary>
p => p.ContainerAnimationStartPosition, /// Defines the <see cref="ContainerAnimationStartPosition"/> property.
(p, o) => p.ContainerAnimationStartPosition = o, 0d); /// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double>
public static readonly DirectProperty<ProgressBarTemplateSettings, double> ContainerAnimationEndPositionProperty = ContainerAnimationStartPositionProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>( AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(ContainerAnimationEndPosition), nameof(ContainerAnimationStartPosition),
p => p.ContainerAnimationEndPosition, p => p.ContainerAnimationStartPosition,
(p, o) => p.ContainerAnimationEndPosition = o, 0d); (p, o) => p.ContainerAnimationStartPosition = o);
public static readonly DirectProperty<ProgressBarTemplateSettings, double> Container2AnimationStartPositionProperty = /// <summary>
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>( /// Defines the <see cref="ContainerAnimationEndPosition"/> property.
nameof(Container2AnimationStartPosition), /// </summary>
p => p.Container2AnimationStartPosition, public static readonly DirectProperty<ProgressBarTemplateSettings, double>
(p, o) => p.Container2AnimationStartPosition = o, 0d); ContainerAnimationEndPositionProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
public static readonly DirectProperty<ProgressBarTemplateSettings, double> Container2AnimationEndPositionProperty = nameof(ContainerAnimationEndPosition),
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>( p => p.ContainerAnimationEndPosition,
nameof(Container2AnimationEndPosition), (p, o) => p.ContainerAnimationEndPosition = o);
p => p.Container2AnimationEndPosition,
(p, o) => p.Container2AnimationEndPosition = o); /// <summary>
/// Defines the <see cref="Container2AnimationStartPosition"/> property.
/// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double>
Container2AnimationStartPositionProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(Container2AnimationStartPosition),
p => p.Container2AnimationStartPosition,
(p, o) => p.Container2AnimationStartPosition = o);
/// <summary>
/// Defines the <see cref="Container2AnimationEndPosition"/> property.
/// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double>
Container2AnimationEndPositionProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(Container2AnimationEndPosition),
p => p.Container2AnimationEndPosition,
(p, o) => p.Container2AnimationEndPosition = o);
/// <summary>
/// Defines the <see cref="Container2Width"/> property.
/// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double> Container2WidthProperty = public static readonly DirectProperty<ProgressBarTemplateSettings, double> Container2WidthProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>( AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(Container2Width), nameof(Container2Width),
p => p.Container2Width, p => p.Container2Width,
(p, o) => p.Container2Width = o); (p, o) => p.Container2Width = o);
/// <summary>
/// Defines the <see cref="ContainerWidth"/> property.
/// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double> ContainerWidthProperty = public static readonly DirectProperty<ProgressBarTemplateSettings, double> ContainerWidthProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>( AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(ContainerWidth), nameof(ContainerWidth),
p => p.ContainerWidth, p => p.ContainerWidth,
(p, o) => p.ContainerWidth = o); (p, o) => p.ContainerWidth = o);
/// <summary>
/// Defines the <see cref="IndeterminateStartingOffset"/> property.
/// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double> IndeterminateStartingOffsetProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(IndeterminateStartingOffset),
p => p.IndeterminateStartingOffset,
(p, o) => p.IndeterminateStartingOffset = o);
/// <summary>
/// Defines the <see cref="IndeterminateEndingOffset"/> property.
/// </summary>
public static readonly DirectProperty<ProgressBarTemplateSettings, double> IndeterminateEndingOffsetProperty =
AvaloniaProperty.RegisterDirect<ProgressBarTemplateSettings, double>(
nameof(IndeterminateEndingOffset),
p => p.IndeterminateEndingOffset,
(p, o) => p.IndeterminateEndingOffset = o);
/// <summary>
/// Used by <see cref="Avalonia.Themes.Fluent"/> to define the first indeterminate indicator's width.
/// </summary>
public double ContainerWidth
{
get => _containerWidth;
set => SetAndRaise(ContainerWidthProperty, ref _containerWidth, value);
}
/// <summary>
/// Used by <see cref="Avalonia.Themes.Fluent"/> to define the second indeterminate indicator's width.
/// </summary>
public double Container2Width
{
get => _container2Width;
set => SetAndRaise(Container2WidthProperty, ref _container2Width, value);
}
/// <summary>
/// Used by <see cref="Avalonia.Themes.Fluent"/> to define the first indeterminate indicator's start position when animated.
/// </summary>
public double ContainerAnimationStartPosition public double ContainerAnimationStartPosition
{ {
get => _containerAnimationStartPosition; get => _containerAnimationStartPosition;
set => SetAndRaise(ContainerAnimationStartPositionProperty, ref _containerAnimationStartPosition, value); set => SetAndRaise(ContainerAnimationStartPositionProperty, ref _containerAnimationStartPosition,
value);
} }
/// <summary>
/// Used by <see cref="Avalonia.Themes.Fluent"/> to define the first indeterminate indicator's end position when animated.
/// </summary>
public double ContainerAnimationEndPosition public double ContainerAnimationEndPosition
{ {
get => _containerAnimationEndPosition; get => _containerAnimationEndPosition;
set => SetAndRaise(ContainerAnimationEndPositionProperty, ref _containerAnimationEndPosition, value); set => SetAndRaise(ContainerAnimationEndPositionProperty, ref _containerAnimationEndPosition, value);
} }
/// <summary>
/// Used by <see cref="Avalonia.Themes.Fluent"/> to define the second indeterminate indicator's start position when animated.
/// </summary>
public double Container2AnimationStartPosition public double Container2AnimationStartPosition
{ {
get => _container2AnimationStartPosition; get => _container2AnimationStartPosition;
set => SetAndRaise(Container2AnimationStartPositionProperty, ref _container2AnimationStartPosition, value); set => SetAndRaise(Container2AnimationStartPositionProperty, ref _container2AnimationStartPosition,
value);
} }
public double Container2Width /// <summary>
/// Used by <see cref="Avalonia.Themes.Fluent"/> to define the second indeterminate indicator's end position when animated.
/// </summary>
public double Container2AnimationEndPosition
{ {
get => _container2Width; get => _container2AnimationEndPosition;
set => SetAndRaise(Container2WidthProperty, ref _container2Width, value); set => SetAndRaise(Container2AnimationEndPositionProperty, ref _container2AnimationEndPosition, value);
} }
public double ContainerWidth /// <summary>
/// Used by <see cref="Avalonia.Themes.Simple"/> to define the starting point of its indeterminate animation.
/// </summary>
public double IndeterminateStartingOffset
{ {
get => _containerWidth; get => _indeterminateStartingOffset;
set => SetAndRaise(ContainerWidthProperty, ref _containerWidth, value); set => SetAndRaise(IndeterminateStartingOffsetProperty, ref _indeterminateStartingOffset, value);
} }
public double Container2AnimationEndPosition /// <summary>
/// Used by <see cref="Avalonia.Themes.Simple"/> to define the ending point of its indeterminate animation.
/// </summary>
public double IndeterminateEndingOffset
{ {
get => _container2AnimationEndPosition; get => _indeterminateEndingOffset;
set => SetAndRaise(Container2AnimationEndPositionProperty, ref _container2AnimationEndPosition, value); set => SetAndRaise(IndeterminateEndingOffsetProperty, ref _indeterminateEndingOffset, value);
} }
} }
@ -131,7 +211,7 @@ namespace Avalonia.Controls
/// Defines the <see cref="Orientation"/> property. /// Defines the <see cref="Orientation"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<Orientation> OrientationProperty = public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<ProgressBar, Orientation>(nameof(Orientation), Orientation.Horizontal); AvaloniaProperty.Register<ProgressBar, Orientation>(nameof(Orientation));
/// <summary> /// <summary>
/// Defines the <see cref="Percentage"/> property. /// Defines the <see cref="Percentage"/> property.
@ -141,18 +221,6 @@ namespace Avalonia.Controls
nameof(Percentage), nameof(Percentage),
o => o.Percentage); o => o.Percentage);
/// <summary>
/// Defines the <see cref="IndeterminateStartingOffset"/> property.
/// </summary>
public static readonly StyledProperty<double> IndeterminateStartingOffsetProperty =
AvaloniaProperty.Register<ProgressBar, double>(nameof(IndeterminateStartingOffset));
/// <summary>
/// Defines the <see cref="IndeterminateEndingOffset"/> property.
/// </summary>
public static readonly StyledProperty<double> IndeterminateEndingOffsetProperty =
AvaloniaProperty.Register<ProgressBar, double>(nameof(IndeterminateEndingOffset));
/// <summary> /// <summary>
/// Gets the overall percentage complete of the progress /// Gets the overall percentage complete of the progress
/// </summary> /// </summary>
@ -162,30 +230,13 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
public double Percentage public double Percentage
{ {
get { return _percentage; } get => _percentage;
private set { SetAndRaise(PercentageProperty, ref _percentage, value); } private set { SetAndRaise(PercentageProperty, ref _percentage, value); }
} }
public double IndeterminateStartingOffset
{
get => GetValue(IndeterminateStartingOffsetProperty);
set => SetValue(IndeterminateStartingOffsetProperty, value);
}
public double IndeterminateEndingOffset
{
get => GetValue(IndeterminateEndingOffsetProperty);
set => SetValue(IndeterminateEndingOffsetProperty, value);
}
static ProgressBar() static ProgressBar()
{ {
ValueProperty.OverrideMetadata<ProgressBar>(new(defaultBindingMode: BindingMode.OneWay)); ValueProperty.OverrideMetadata<ProgressBar>(new(defaultBindingMode: BindingMode.OneWay));
ValueProperty.Changed.AddClassHandler<ProgressBar>((x, e) => x.UpdateIndicatorWhenPropChanged(e));
MinimumProperty.Changed.AddClassHandler<ProgressBar>((x, e) => x.UpdateIndicatorWhenPropChanged(e));
MaximumProperty.Changed.AddClassHandler<ProgressBar>((x, e) => x.UpdateIndicatorWhenPropChanged(e));
IsIndeterminateProperty.Changed.AddClassHandler<ProgressBar>((x, e) => x.UpdateIndicatorWhenPropChanged(e));
OrientationProperty.Changed.AddClassHandler<ProgressBar>((x, e) => x.UpdateIndicatorWhenPropChanged(e));
} }
/// <summary> /// <summary>
@ -251,6 +302,15 @@ namespace Avalonia.Controls
{ {
base.OnPropertyChanged(change); base.OnPropertyChanged(change);
if (change.Property == ValueProperty ||
change.Property == MinimumProperty ||
change.Property == MaximumProperty ||
change.Property == IsIndeterminateProperty ||
change.Property == OrientationProperty)
{
UpdateIndicator();
}
if (change.Property == IsIndeterminateProperty) if (change.Property == IsIndeterminateProperty)
{ {
UpdatePseudoClasses(change.GetNewValue<bool>(), null); UpdatePseudoClasses(change.GetNewValue<bool>(), null);
@ -286,64 +346,50 @@ namespace Avalonia.Controls
// Gets the size of the parent indicator container // Gets the size of the parent indicator container
var barSize = _indicator?.VisualParent?.Bounds.Size ?? Bounds.Size; var barSize = _indicator?.VisualParent?.Bounds.Size ?? Bounds.Size;
if (_indicator != null) if (_indicator == null) return;
if (IsIndeterminate)
{ {
if (IsIndeterminate) // Pulled from ModernWPF.
{
// Pulled from ModernWPF.
var dim = Orientation == Orientation.Horizontal ? barSize.Width : barSize.Height; var dim = Orientation == Orientation.Horizontal ? barSize.Width : barSize.Height;
var barIndicatorWidth = dim * 0.4; // Indicator width at 40% of ProgressBar var barIndicatorWidth = dim * 0.4; // Indicator width at 40% of ProgressBar
var barIndicatorWidth2 = dim * 0.6; // Indicator width at 60% of ProgressBar var barIndicatorWidth2 = dim * 0.6; // Indicator width at 60% of ProgressBar
TemplateSettings.ContainerWidth = barIndicatorWidth; TemplateSettings.ContainerWidth = barIndicatorWidth;
TemplateSettings.Container2Width = barIndicatorWidth2; TemplateSettings.Container2Width = barIndicatorWidth2;
TemplateSettings.ContainerAnimationStartPosition = barIndicatorWidth * -1.8; // Position at -180% TemplateSettings.ContainerAnimationStartPosition = barIndicatorWidth * -1.8; // Position at -180%
TemplateSettings.ContainerAnimationEndPosition = barIndicatorWidth * 3.0; // Position at 300% TemplateSettings.ContainerAnimationEndPosition = barIndicatorWidth * 3.0; // Position at 300%
TemplateSettings.Container2AnimationStartPosition = barIndicatorWidth2 * -1.5; // Position at -150% TemplateSettings.Container2AnimationStartPosition = barIndicatorWidth2 * -1.5; // Position at -150%
TemplateSettings.Container2AnimationEndPosition = barIndicatorWidth2 * 1.66; // Position at 166% TemplateSettings.Container2AnimationEndPosition = barIndicatorWidth2 * 1.66; // Position at 166%
// Remove these properties when we switch to fluent as default and removed the old one. TemplateSettings.IndeterminateStartingOffset = -dim;
SetCurrentValue(IndeterminateStartingOffsetProperty,-dim); TemplateSettings.IndeterminateEndingOffset = dim;
SetCurrentValue(IndeterminateEndingOffsetProperty,dim); }
else
{
var percent = Math.Abs(Maximum - Minimum) < double.Epsilon ?
1.0 :
(Value - Minimum) / (Maximum - Minimum);
var padding = Padding; // When the Orientation changed, the indicator's Width or Height should set to double.NaN.
var rectangle = new RectangleGeometry( // Indicator size calculation should consider the ProgressBar's Padding property setting
new Rect( if (Orientation == Orientation.Horizontal)
padding.Left, {
padding.Top, _indicator.Width = (barSize.Width - _indicator.Margin.Left - _indicator.Margin.Right) * percent;
barSize.Width - (padding.Right + padding.Left), _indicator.Height = double.NaN;
barSize.Height - (padding.Bottom + padding.Top)
));
} }
else else
{ {
double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum); _indicator.Width = double.NaN;
_indicator.Height = (barSize.Height - _indicator.Margin.Top - _indicator.Margin.Bottom) *
// When the Orientation changed, the indicator's Width or Height should set to double.NaN. percent;
// Indicator size calculation should consider the ProgressBar's Padding property setting
if (Orientation == Orientation.Horizontal)
{
_indicator.Width = (barSize.Width - _indicator.Margin.Left - _indicator.Margin.Right) * percent;
_indicator.Height = double.NaN;
}
else
{
_indicator.Width = double.NaN;
_indicator.Height = (barSize.Height - _indicator.Margin.Top - _indicator.Margin.Bottom) * percent;
}
Percentage = percent * 100;
} }
}
}
private void UpdateIndicatorWhenPropChanged(AvaloniaPropertyChangedEventArgs e)
{ Percentage = percent * 100;
UpdateIndicator(); }
} }
private void UpdatePseudoClasses( private void UpdatePseudoClasses(
@ -355,11 +401,9 @@ namespace Avalonia.Controls
PseudoClasses.Set(":indeterminate", isIndeterminate.Value); PseudoClasses.Set(":indeterminate", isIndeterminate.Value);
} }
if (o.HasValue) if (!o.HasValue) return;
{ PseudoClasses.Set(":vertical", o == Orientation.Vertical);
PseudoClasses.Set(":vertical", o == Orientation.Vertical); PseudoClasses.Set(":horizontal", o == Orientation.Horizontal);
PseudoClasses.Set(":horizontal", o == Orientation.Horizontal);
}
} }
} }
} }

8
src/Avalonia.Themes.Simple/Controls/ProgressBar.xaml

@ -87,10 +87,10 @@
IterationCount="Infinite" IterationCount="Infinite"
Duration="0:0:3"> Duration="0:0:3">
<KeyFrame Cue="0%"> <KeyFrame Cue="0%">
<Setter Property="TranslateTransform.X" Value="{Binding IndeterminateStartingOffset, RelativeSource={RelativeSource TemplatedParent}}" /> <Setter Property="TranslateTransform.X" Value="{Binding $parent[ProgressBar].TemplateSettings.IndeterminateStartingOffset}" />
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%"> <KeyFrame Cue="100%">
<Setter Property="TranslateTransform.X" Value="{Binding IndeterminateEndingOffset, RelativeSource={RelativeSource TemplatedParent}}" /> <Setter Property="TranslateTransform.X" Value="{Binding $parent[ProgressBar].TemplateSettings.IndeterminateEndingOffset}" />
</KeyFrame> </KeyFrame>
</Animation> </Animation>
</Style.Animations> </Style.Animations>
@ -102,10 +102,10 @@
IterationCount="Infinite" IterationCount="Infinite"
Duration="0:0:3"> Duration="0:0:3">
<KeyFrame Cue="0%"> <KeyFrame Cue="0%">
<Setter Property="TranslateTransform.Y" Value="{Binding IndeterminateStartingOffset, RelativeSource={RelativeSource TemplatedParent}}" /> <Setter Property="TranslateTransform.Y" Value="{Binding $parent[ProgressBar].TemplateSettings.IndeterminateStartingOffset}" />
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%"> <KeyFrame Cue="100%">
<Setter Property="TranslateTransform.Y" Value="{Binding IndeterminateEndingOffset, RelativeSource={RelativeSource TemplatedParent}}" /> <Setter Property="TranslateTransform.Y" Value="{Binding $parent[ProgressBar].TemplateSettings.IndeterminateEndingOffset}" />
</KeyFrame> </KeyFrame>
</Animation> </Animation>
</Style.Animations> </Style.Animations>

Loading…
Cancel
Save